指针8道笔试题解析

时间:2023-03-07 21:01:48

笔试题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;
}
//程序的结果是什么?

第一个是首元素的地址再加一,指向第二个元素,再解引用,最后打印的就是2;

第二个,&a+1,取出整个地址再加一,指向5的后面,是一个数组指针,然后强转成整型指针;再减一,最后打印的就是5

指针8道笔试题解析



笔试题2:

//由于还没学习结构体,这里告知结构体的大小是20个字节
struct Test
{
int Num;
char *pcName;
short sDate;
char cha[2];
short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
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;
}

p是结构体指针,p+0x1就是p+1,跳过一个结构体的大小,这里结构体的大小是20,所以打印的结果就是00100014(20换算成16进制就是14,位数不够在前面补0,因为测试是在x86的环境下,所以指针是8位16进制);

第二个把p强转成unsigned long型,也就是整数类型,加一就是加一,打印00100001;

第三个把p强转成unsigned int*类型,加一跳过一个整型的大小,打印00100004;

指针8道笔试题解析

如果把%p换成%x,打印的就是16进制的数字,而不是地址,前面的0就没有意义了:

指针8道笔试题解析


第三题:

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;
}

&a是数组指针,+1跳过整个数组,再强转为整型指针,ptr1[-1]其实就等于*(ptr1-1),也就是4,打印也就是4;

对于第二个打印,a表示首元素地址,在这里是0x006ffe48,(下图)强转成整型,即7339592,再加一,得到7339593,再强转为整型指针,就是0x006ffe49;所以ptr2就是0x006ffe49;也就是指针加一,跳过一个字节,这时请看下面我画的图:

指针8道笔试题解析

指针8道笔试题解析

ptr2即指向“01”的后面,然后解引用,因为是int型指针,所以向后解引用4个字节,到“02”的后面,因为是小端存,所以再以小端的形式拿出来,即0x 02 00 00 00(16进制),因为是以16进制打印,所以就是2000000。

指针8道笔试题解析

对于我自己而言,这题还是很重量级的,由于对于地址加一的理解不够,我自己是想了好久好久。



第四题:

#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;
}

这题,我们可以注意到(0,1),(2,3),(4,5);这其实是逗号表达式,最后一个表达式的结果就是它的结果,所以其实是 int a[3][2] = { 1 , 3 , 5 } ;剩下三个就是0,a[0]是数组名,即第一行第一个元素的地址,所以p就指向1,p[0]可以写成*(p+0),就是1;

指针8道笔试题解析



第五题:

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;
}

第五题也是重量级的,像这种题目就要好好画图了,让我们仔细研究一下:

指针8道笔试题解析

a[4][2]已经在图中标注出来了;接着将 a 赋给 p ,a表示首行的地址,是数组指针,类型是int(*)[5],放入 p 中(p的类型是int (*)[4]),因为类型不同,编译器会说一下,但是也只是说一下而已,是可以放进去的,接着,p[4][2]可以写成*(*(p+4)+2);p+4跳过16个字节的大小(注意p的数组元素个数是4,不是5,不要跳过20个字节了),再解引用,得到图中蓝色的部分,这时p+4作为数组名,表示首元素的地址,再+2,跳过两个字节,再解引用,得到图中的绿色的元素;

看到打印的结果是两个指针的相减,显然后面一个是-4;而-4的原反补码是:

10000000 00000000 00000000 00000100

11111111 11111111 11111111 11111011

11111111 11111111 11111111 11111100

换算成16进制,即0x ff ff ff fc;对于地址而言,其实没有原反补码的概念,打印出来的就是0x ff ff ff fc;

指针8道笔试题解析



第六题:

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;
}


&aa得到整个二维数组的地址,再+1,跳过整个二位数组,指向10的后面,再强转为整型指针,ptr1就指向10的后面,再减一,就指向了10,解引用得到10,打印的就是10;

aa表示第一行的地址,再加一,表示第二行的地址,再解引用,得到的其实是第二行的数组名,如果不能理解的话,还可以把*(aa+1)改写成aa[1],即第二行的数组名,即第二行首元素的地址,这时的强转其实已经多余了,再减一,得到的就是5;

指针8道笔试题解析



第七题:

#include <stdio.h>
int main()
{
char *a[] = {"work","at","alibaba"};
char**pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}

a是一个指针数组,每一个元素是一个指针,指向字符串的首个字符;数组名a表示首元素的地址,也就是第一个指针的地址,将其地址放入pa中,类型是二级指针,接着pa++;跳过一个字符指针的大小,指向第二个指针,再解引用pa,得到的是第二个指针,也就是 'at' 的首元素 'a' 的地址,我们知道,printf函数的参数是指针,所以打印首字符的地址也就是打印整个字符串,也就是 "at" ;

指针8道笔试题解析

-->

指针8道笔试题解析

指针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); point
printf("%s\n", *--*++cpp+3);
printf("%s\n", *cpp[-2]+3);
printf("%s\n", cpp[-1][-1]+1);
return 0;
}

像这样复杂的题目,画图是最好的方法:

指针8道笔试题解析

画好图之后,我们看第一个:printf("%s\n", **++cpp); 

首先执行++cpp,也就是cpp自增,指向了c+2,再解引用,得到了c+2里面的内容,即指向了 c 中的第三个指针元素,再解引用,得到了char*的内容,即指向了"POINT"的首元素'p',所以打印的应该就是POINT(等全部分析完再看结果):

指针8道笔试题解析

接着,我们看第二个:printf("%s\n", *--*++cpp+3);

首先执行的是++cpp,因为上面cpp已经指向了c+2,所以这是的cpp指向了c+1,解引用的优先级是高于加号的,所以我们接下来解引用,得到c+1的内容,即指向了 c 中的第二个指针元素,再--,即指针指向了 c 中的第一个元素指针,再解引用,得到第一个char*的内容,即指向了"ENTER"的首元素'E',接着再+3,指向了'E',所以打印的结果应该是"ER":

指针8道笔试题解析

继续,我们看到第三个:printf("%s\n", *cpp[-2]+3);

cpp[-2]可以写成 *(cpp-2),所以结果就指向了c+3(但是cpp还是指向的c+1),再解引用得到c+3的内容,即指向了 c 的第四个元素,再解引用,得到第四个元素的内容,即指向了"FIRST"的'F',再+3,即指向了'S',所以打印的结果应该是"ST":

指针8道笔试题解析

终于到最后一个了:printf("%s\n", cpp[-1][-1]+1); 

cpp[-1][-1]可以写成 ((app-1)-1),cpp减一,指向了c+2,再解引用,得到c+2的内容,再减一,指向了c 的第二个元素,再解引用,得到它的内容,即指向了"NEW"的首字符'N',再加一,指向了'E',所以最后打印的结果应该是"EW":

指针8道笔试题解析

接下来,见证奇迹的时刻到了!

指针8道笔试题解析

只能说:完美!


好了,以上就是指针8道笔试题的所有内容了,希望对你有所帮助喽。