数组和指针笔试题解析之【指针】

2023-09-21 00:44:53

目录

🍂笔试题1:

 🍂笔试题2:

  🍂笔试题3:

  🍂笔试题4:

   🍂笔试题5:

   🍂笔试题6: 

    🍂笔试题7:

    🍂笔试题8:


🍂笔试题1:

int main()
{
	int a[5] = { 1, 2, 3, 4, 5 };
	int* ptr = (int*)(&a + 1);
	printf("%d,%d", *(a + 1), *(ptr - 1));
	return 0;
}

运行结果: 

🎈解析: 

1.a是数组首元素的地址,+1得到第二个元素的地址,对其解引用得到的就是2;

2.&a取出整个数组的地址,+1跳过整个数组,对跳过的整个数组-1,得到的就是数组最后一位元素的地址,对其解引用的结果就是5


🍂笔试题2:

//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
struct Test
{
	int Num;
	char* pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p;

int main()
{
    p = (struct Test*)0x100000;
	printf("%p\n", p + 0x1);
	printf("%p\n", (unsigned long)p + 0x1);
	printf("%p\n", (unsigned int*)p + 0x1);
	return 0;
}

运行结果: 

🎈解析: 

 1.已知结构体变量的大小是20个字节,因为p是结构体指针类型,所以+1就是跳过20个字节,又因为十进制的20 等价于16进制的14,所以打印出来的结果为00100014

2.这里将其强制类型转换成unsigned long,表示整数,整数+1就是+1,所以打印出来的结果为00100001

3.这里将其强制类型转换成unsigned int*,表示整型指针,+1就是向后跳过4个字节,所以打印出来的结果为00100004


🍂笔试题3:

int main()
{
int a[4] = { 1, 2, 3, 4 };
int *ptr1 = (int *)(&a + 1);
int *ptr2 = (int *)((int)a + 1);
printf( "%x,%x", ptr1[-1], *ptr2);
return 0;
}

运行结果: 

🎈解析:

1.&a取出的是整个数组的地址,+1就跳过整个数组,ptr1[-1] == *(ptr1-1),得到的就是下标为3的元素4

2.这里的a为数组名,即数组首元素的地址,强制类型转换为整型,+1就是加上数值1,即1个字节,ptr2就指向了第一个元素第二个字节处,对其解引用操作,访问4个字节的位置,因为数组在内存中是连续存储的,且是小端存储,即02 00 00 00,所以将其以%x的形式打印就为2000000


🍂笔试题4:

int main()
{
int a[3][2] = { (0, 1), (2, 3), (4, 5) };
int *p;
p = a[0];
printf( "%d", p[0]);
return 0;
}

 运行结果: 

🎈解析:

 做这道题的时候我们一定要擦亮眼睛,注意这个二维数组初始化的时候里边写的是逗号表达式,而不是{ }。逗号表达式的运算法则是从左向右计算,最后一个表达式的结果为整个逗号表达式的结果,所以数组初始化的元素为{1,3,5},其余的元素均为0。a[0] == a[0][0],a[0]是第一行的数组名,数组名是数组首元素的地址,即元素1的地址,把它存放在指针变量p当中去,p[0] == *(p+0) == *p,即对p进行解引用操作,打印出来就为1。


🍂笔试题5:

int main()
{
int a[5][5];
int(*p)[4];
p = a;
printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
return 0;
}

  运行结果: 

🎈解析:

 1.a为数组首元素的地址,即第一行的地址,它的类型是int (*) [5],p的类型是int (*) [4],虽然它们的类型不同,但并不影响将a的地址放在p里边去。

2.观察上图,我们可以看见&p[4][2]和&a[4][2]在内存中所指向的位置,这两者都是指针,指针减去指针得到的是中间元素的个数,因为随着数组下标的增长地址是由低到高变化的,所以%d打印的结果就为-4。%p打印的是地址,认为内存中存储的补码就是地址,所以结果为FFFFFFFC


🍂笔试题6: 

int main()
{
int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int *ptr1 = (int *)(&aa + 1);
int *ptr2 = (int *)(*(aa + 1));
printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1));
return 0;
}

   运行结果:

🎈解析:

1. &aa取出的是整个二维数组的地址,&aa+1跳过一个二维数组的大小,强制类型转换成int*类型,ptr1此时也指向了这个位置,所以*(ptr-1)打印的结果就为10

2.aa是数组名,表示数组首元素的地址,即第一行的地址,+1跳过一个int [5]的大小,指向第二行,对其进行解引用操作,此时,ptr2指向了6,*(ptr2-1)打印的结果就为5


🍂笔试题7:

int main()
{
char *a[] = {"work","at","alibaba"};
char**pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}

    运行结果:

 🎈解析:

这里给出了一个名为a的指针数组,每个数组的类型是char*类型,实际存放的并不是"work","at","alibaba",而是字符串首元素的地址,第一个char*指向了'w'的地址,第二个char*指向了'a'的地址,第三个char*指向了'a'的地址;数组名a是数组首元素的地址,char*的地址为char**类型,存放到pa这个二级指针中,pa++就跳过了一个char*的类型,*pa就拿到了数组第二个元素,即'a'的地址,%s打印就为at


🍂笔试题8:

int main()
{
char *c[] = {"ENTER","NEW","POINT","FIRST"};
char**cp[] = {c+3,c+2,c+1,c};
char***cpp = cp;
printf("%s\n", **++cpp);
printf("%s\n", *--*++cpp+3);
printf("%s\n", *cpp[-2]+3);
printf("%s\n", cpp[-1][-1]+1);
return 0;
}

 运行结果:

 

 🎈解析:

 1.**++cpp,程序首先会执行++cpp操作,cpp会跳过一个char**的类型,此时就指向了c+2,对其解引用操作,我们拿到了c+2的这块空间里面的数据,即c+2,而c+2又是c数组下标为2的元素空间的地址,对其进行解引用操作,就拿到了c数组下标为2的空间,这块空间存放了‘P’的地址,%s就会根据P的地址向后打印字符串,打印的结果就是POINT

2. *-- * ++cpp + 3,按优先级来算,先从++cpp开始计算,此时的cpp不再指向c+2,而是指向了c+1,然后进行解引用操作,就拿到了c+1这块空间里面的数据,在进行--操作,相当于c+1减去1,那么这块空间的数据就是c了,在对其进行解引用操作,它就指向了c数组的第一个元素,即'E'的地址,最后+3,此时指针指向第二个'E',%s就会根据此时的地址向后打印字符串,结果就是ER 

3. *cpp[-2] + 3 ,cpp[-2]可以看作是*(cpp - 2),即 **(cpp - 2)+ 3 ,cpp - 2指向了cp数组的第一个元素的空间,解引用操作,拿到了c+3这块空间,这块空间指向了c数组的下标为3的元素空间,解引用操作,拿到了这块空间,即'F'的地址,最后+3,指针指向了'S',%s就会根据此时的地址向后打印字符串,结果打印就是ST 

4. cpp[-1][-1] + 1,cpp[-1][-1] 可以看作是*(*(cpp - 1) - 1) ,即 *(*(cpp - 1) - 1)+1,cpp - 1指向了cp数组的第二个元素的空间,解引用操作,拿到了c+2这块空间, - 1即c+2减去1,那么这块空间的数据就是c+1了,此时指向了c数组的第二个元素,解引用操作,拿到了这块空间的元素, 即'N'的地址,最后+1,指针指向了'E',%s就会根据此时的地址向后打印字符串,结果就是EW 

更多推荐

计算机视觉与深度学习-图像分割-视觉识别任务02-目标检测-【北邮鲁鹏】

目录标题参考目标检测定义深度学习对目标检测的作用单目标检测多任务框架多任务损失预训练模型姿态估计多目标检测问题滑动窗口(SlidingWindow)滑动窗口缺点AdaBoost(AdaptiveBoosting)参考区域建议selectivesearch思想慢速R-CNN慢速R-CNN思路边界框回归(Bboxreg)慢

leetcode分类刷题:队列(Queue)(二、优先队列解决TopK简单问题)

1、优先队列好像一般都叫堆,以大顶堆为例,顶部第一个元素最大,底部最后一个元素最小,自顶向底是递减的(更准确的说是非递增的),对外只能访问顶部第一个元素(对应索引为0)和底部最后一个元素(对应索引为-1);在Python中,heapq默认维护小顶堆,构造大顶堆时需要在入堆时添加相反数2、本次博客总结下用优先队列解决To

JavaScript系列从入门到精通系列第三篇:JavaScript基本语法(一)

文章目录一:JavaScript基本语法1:JS注释(一):JS多行注释(二):JS单行注释(三):JS中大小写(四):分号问题(五):空格和换行2:字面量和变量(一):字面量(二):变量(三):如何声明变量(四):如何给变量赋值(五):标识符二:JS中6种数据类型(一)1:JS字符串(一):JS字符串基本使用(二):

Ubuntu 安装 CUDA 与 OPENCL

前言:最近需要做一些GPU并行计算,因而入坑CUDA和OPENCL,两者都有用到一些,刚好有点时间,同时记录一些学习过程,排掉一些坑,这篇是环境安装篇,基本跟着走就没什么问题,环境:ubuntu18.04/ubuntu20.04显卡:Nvidia一、CUDA安装1.查看电脑是否识别GPUlspci|grep-invid

Liunx(Ubuntu20)常用指令

-rwxr-xr-x,在Linux系统中权限是区分用户的,即用户、组用户、其他用户,第一位表示文件的类型,-代表文件,d代表目录,其他每个用户占三个字符用户、组用户、其他用户都是rwx形式,其中r表示读、w表示写、x表示可执行,-表示没有权限,拿用户组举例,r只能出现在第一个位置、w只能出现在第二个位置、x只能出现在第

在 CentOS 上安装 Docker Engine

文章目录在CentOS上安装DockerEngine先决条件操作系统要求卸载旧版本安装方法使用rpm存储库安装设置存储库安装DockerEngine安装最新版本安装指定版本以非root用户身份管理Docker配置Docker以使用systemd启动参考官方文档:https://docs.docker.com/engin

阿里云服务器价格表,轻量和服务器最新活动价格表汇总

租用阿里云服务器怎么收费?阿里云服务器配置不同一年价格也不同,阿里云2核2G3M带宽108元一年、2核4G4M带宽297.98元12个月,云服务器u1公网带宽可选1M到5M,系统盘为ESSD云盘40GB起,CPU内存配置可选2核2G、2核4G、4核8G、8核16G等配置,还有ECS计算型c7、通用型g7和内存型r7多C

【SLAM】前端-视觉里程计之对极几何

文章目录【SLAM】前端-视觉里程计之对极几何1.对极几何2.本质矩阵及其求解3.单应矩阵及其求解3.三角测量4.思考4.1本质矩阵的自由度为多少4.2直接法求本质矩阵的过程涉及求解齐次线性方程,而对于齐次线性方程的解,要么只有零解,要么有无穷多个解,这里取哪一个解呢5.附录5.1相机成像模型【SLAM】前端-视觉里程

接口测试——接口协议抓包分析与mock_L1

目录:接口测试价值与体系常见的接口协议接口测试用例设计postman基础使用postman实战练习1.接口测试价值与体系接口测试概念接口:不同的系统之间相互连接的部分,是一个传递数据的通道接口测试:检查数据的交换、传递和控制管理过程接口测试的价值传统的测试方法成本急剧上升测试效率下降分层测试体系越往上,发现Bug的时间

CSS 布局 (三) 浮动、定位、多列布局

6、浮动最初用于在文本块内浮动图像,float属性成为在网页上创建多列布局最常用的工具之一。随着flexbox和grid的出现,它现在又回到了最初的目的,正如本文所解释的那样。6.1浮动的背景引入float属性是为了允许web开发人员实现包含图像在文本列内浮动的布局,文本在其左侧或右侧环绕。就像你在报纸版面上看到的那样

函数扩展之——内存函数

前言:小伙伴们又见面啦。本篇文章,我们将讲解C语言中比较重要且常用的内存函数,并尝试模拟实现它们的功能。让我们一起来学习叭。目录一.什么是内存函数二.内存函数有哪些1.memcpy(1)库函数memcpy(2)模拟实现memcpy2.memmove(1)库函数memmove(2)模拟实现memmove3.memset4

热文推荐