家人们欢迎来到小姜的世界,<<点此>>传送门 这里有详细的关于C/C++/Linux等的解析课程,家人们赶紧冲鸭!!!
指针笔试题
- 前言
- 一、题1
- (一)题目
- (二)答案及解析
- (三)代码
- 二、题2
- (一)题目
- (二)答案及解析
- (三)代码
- 三、题3
- (一)题目
- (二)答案及解析
- (三)代码
- 四、题4
- (一)题目
- (二)答案及解析
- (三)代码
- 五、题5
- (一)题目
- (二)答案及解析
- (三)代码
- 六、题6
- (一)题目
- (二)答案及解析
- (三)代码
- 七、题7
- (一)题目
- (二)答案及解析
- (三)代码
- 八、题8
- (一)题目
- (二)答案及解析
- (三)代码
- 总结
前言
指针的笔试题有许多,这都是C语言基础时候的笔试题,下面有8道笔试的题目,是很精炼的几道笔试题,主要分为三个模块,题目,答案及解析和代码,这里放上代码是为了供大家去进行复制粘贴到编译器里面试一试,在完成这些题目的时候需要细心与耐心,慢慢来,结合前面的知识图谱进行解读,这需要的是前面很好的指针基础以及了解前面的知识,但大家放心,我会仔仔细细,慢慢讲解这些题目,让大家完全了解和掌握。
一、题1
(一)题目
(二)答案及解析
答案:2,5
解析:大家看图,&a拿到的是整个数组的地址,也就是拿到蓝色方框的地址,&a的类型是int(*)[5],是个数组指针,+1这个操作是跳过整个数组跳到下一个数组,而这串数组是存放在cpu里面的,前后都不知道存放的是什么,只有a这个数组是被维护的。题目中的ptr又要是个(int*)的指针类型,那就需要将&a的类型进行强制类型转换成int*,所以题目问的是*(ptr-1),那不就是这个a数组的末尾元素吗,那就是5了,至于*(a+1)那就更简单了,a为首元素的地址,+1就是第二个元素的地址,一解引用那就直接为2。
(三)代码
int main()
{
int a[5] = { 1, 2, 3, 4, 5 };
int* ptr = (int*)(&a + 1);
printf("%d,%d", *(a + 1), *(ptr - 1));
return 0;
}
二、题2
(一)题目
(二)答案及解析
答案:0x00100014 0x00100001 0x00100004(0x表示十六进制)
解析:此题考察的就是指针+1,大家看图,我们规定p的值就是0x100000。
第一个printf是指针+1,跳过的是一整个结构体的大小,因为上面定义了*p就是用Text结构体定义的,那就是struct Text *p;所以+1跳过了一整个结构体,这个结构体的大小是20个字节,那我们跳过20个字节,在十六进制中是“14”,而我们是在32位机器下运行的,那这个类型是4个字节,前面补0,所以第一个答案是0x00100014。
第二个printf是将结构体指针p转化为无符号整型的p,整型+1的结果就是在原本的值的基础上+1,所以就是0x00100001。
第三个printf是将结构体指针p转换成为无符号整型指针,既然是指针,跳过的就是整型指针类型,那就是跳过4个字节,答案就是0x00100004。
ps:%p打印的是地址,32位机器上是占4个字节的,也就是0x00 00 00 00八位。
(三)代码
//假设这个Text结构体的大小是20个字节
struct Test
{
int Num;
char* pcName;
short sDate;
char cha[2];
short sBa[4];
}*p;
//假设p 的值为0x100000
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;
}
三、题3
(一)题目
(二)答案及解析
答案:0x4 0x2000000(0x表示十六进制)
解析:大家看图。我们先分析ptr1指针,&a是取出的一整个数组的地址,而+1以后是跳过这一整个数组往后找下一个数组,那后面打印的是ptr[-1]相当于ptr1-1,ptr1-1是往后一个整型指针类型的大小,那么指向的就是4,那么答案就是4。
再分析一下ptr2,这时候我们需要展开所有字节来看了,这就是指针的魅力所在,我们发现a应该是首元素的地址,但解引用成(int),所以a就是一个简单的整型,不是指针,所以单纯的+1就是单纯的跳过一个字节,因为4+1=5(跳过的是1个字节),指针4+1=8(跳过的是4个字节),那所以(int)a+1指向的就是00这个字节,而当(int)a+1整个强制类型转换成为(int*),整型指针占4个字节,那就是从(int)a+1这个指向的字节位置往后找4个字节即可,那就是00 00 00 02,而我们题目给定的条件是小端存放,且在x86的情况下,那么我们进行拿出来显示的时候是02000000,所以%p结果就是0x02000000,而这道题目要求的是%x,也就是十六进制,则前导的0要删掉。
ps:%x表示的是十六进制,前导的0都需要删掉。
(三)代码
//小端,X86环境
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;
}
四、题4
(一)题目
(二)答案及解析
答案:1
解析:这道题目是在是太贼了,这花括号里面不是花括号,而是逗号,我思考了半天这道题,死来想去应该是0,而答案却是1,原来是有个(,),逗号表达式返回的是后面的值,所以值为1,3,5,0,0,0。我们知道二维数组的值那就好办了,a[0]就是二维数组的首行数组名,那也就是p这个指针指向的是a这个二维数组首行的地址,也就是两个元素,而p[0]又是*(p+0)==*p,那也就是1了。
(三)代码
#include <stdio.h>
int main()
{
int a[3][2] = { (0, 1), (2, 3), (4, 5) };
int* p;
p = a[0];
printf("%d", p[0]);
return 0;
}
五、题5
(一)题目
(二)答案及解析
答案:0xFFFFFFFC -4
解析:这道题目坑是真的多呀,我们先看二维数组a的类型,是int(*)[5]是一组中有五个元素的,而p的类型是int(*)[4],是一组中有4个元素的,这两个类型都不匹配,还不强制类型转换,直接即将a赋给p了,这让p太为难了,p说没事儿,我接收你,那好,p现在是将a的内存空间进行划分,四个元素四个元素划分一个,所以我们要求的p[4][2]就是褐色那片区域,而指针指向的是褐色所在的那片区域的最左边,而我们要求的a[4][2]就是绿色区域了,根据指针相减,发现是低地址减高地址,那就是-4了,可是此题没完,前面要的是%p,那是个地址,我们知道在计算机内存中数字是以二进制的补码存储的,那这就很简单了,地址又不看补码的,直接换算成地址,那就是0xFFFFFFFC了。
(三)代码
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;
}
六、题6
(一)题目
(二)答案及解析
答案:10 5
解析:如下图所示,我们先知道的是&aa取的是整个数组的地址,那+1是跳过整个二维数组,那就是指向10的末尾,那-1是指向的是10,再解引用就拿出来的结果为10,而aa是首个数组的地址,+1是跳过首个数组到第二个数组的头,但此时也是取的是第二个数组,但是进行强制类型转换了,所以ptr2指针-1是跳过一个元素,所以显示的是5。
(三)代码
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;
}
七、题7
(一)题目
(二)答案及解析
答案:at
解析:我们先看字符指针数组char* a[],这个指针指向的是后面三个字符串的首元素,而char** pa=a,所以pa指向的是字符指针a的首元素,这个关系我们清楚了以后,看一看pa++的含义,我们此时想了,char** pa的含义是:char* *pa,这个意思是对pa进行加一的操作,是跳过的一个char*元素,所以指向的是’a’,进行解引用打印字符串打印的就是at。
(三)代码
#include <stdio.h>
int main()
{
char* a[] = { "work","at","alibaba" };
char** pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}
八、题8
(一)题目
(二)答案及解析
答案:POINT ER ST EW
解析:总的分析:
分开单独分析:
(三)代码
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;
}
总结
终于归纳完这些练习题了,这些练习题实在是太坑了,那么多的坑等着你去踩,但是我们需要一步步去了解一下它们,它们也不是那么难以理解与制作,那就需要有学习的方法,利用画图或者是反推是非常重要的,所以对于我们来说,我们需要把这些题目当成朋友去看待,相信总能解决的,感谢大家耐心阅读!!!
客官,码字不易,来个三连支持一下吧!!!