经典指针面试题(下)

142 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

接着上一章节,我们直接进入正题: 经典指针面试题详解(上)

笔试题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;
}

输出结果为:FFFFFFFC,-4

分析: 在这里插入图片描述 p是指向包含四个整型的数组指针,p=a相当于把数组a的首元素地址赋给p, p[4]\2]等价于*(*(p+4)+2),p是int*[4]类型的指针,加4后跳过16个字节,如图所示;由于p是一个数组指针,所以解引用之后得到的是一个数组(橘色部分),所以*(p+4)就相当于一个数组名,数组名再加2得到数组的第三个元素的地址,再解引用,得到数组第三个元素(灰色部分),所以&p[4][2]也就是这个灰色部分所存放元素的地址,&p[4][2] - &a[4][2]得到的是这两个地址之间的元素个数的相反数(因为前者是低地址,后者是高地址),以%d形式输出就是-4;以%p形式输出的是-4的补码的十六进制形式,也就是0xFFFFFFFC;

笔试题6:

	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));//10,5
	return 0;

输出结果:10,5

分析:&aa得到二维数组的地址,加1后得到跳过整个二维数组后的地址,将其强制类型转化为int类型的指针后,步长变成4,所以(ptr1-1)访问的是ptr1往前四个字节的内容,也就是10; aa是数组名,也就是首元素(第一行元素)的地址,加1后跳过一行,得到第二行元素的地址(或者解释为:*(aa+1)等价于aa[1],也就是第二行的一维数组的数组名),强制类型转换成int*后,*(ptr2-1)访问的是第二行往前四个字节的内容,也就是5;

笔试题7:

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

输出结果:at

分析:将数组a的首元素("work")地址存放在二级字符指针pa中,pa++即向后跳过1个字节,由于数组a中存放的是三个字符串的首元素地址,各占用1个字节,所以pa++得到指向 "at"的指针,所以输出at;

笔试题8:

	char* c[] = { "ENTER","NEW","POINT","FIRST"};
	char**cp[] = { c + 3,c + 2,c + 1,c };
	char*** cpp = cp;
	printf("%s\n", **++cpp);---注意,此时cpp由于++,已经发生改变
	printf("%s\n", *- -*++cpp + 3);
	printf("%s\n", *cpp[-2] + 3);
	printf("%s\n", cpp[-1][-1] + 1);

输出结果:POINT、ER、ST、EW 分析:解引用符 * 和++都属于第二优先级运算符,结合方向为从右向左,所以 对于: 在这里插入图片描述 先运算++cpp得到c+2的地址,解引用一次得到c+2,再解引用得到 "POINT" 的首字符地址,然后输出POINT; 对于: 在这里插入图片描述 首先运算++cpp,得到c+1的地址,解引用得到c+1,c+1指向"NEW"的首字符地址,- -后得到"ENTER"的首字符地址,+3后得到字符E的地址,所以%s输出ER;

[]优先级高于*,所以先执行cpp[-2],也就是*(cpp-2),得到c+3,解引用得到"FIRST"的首字符地址,再+3后得到S的地址,所以%s打印ST; cpp[-1][-1]等价于*(*(cpp-1)-1),其中cpp-1表示c+2的地址,解引用后得到c+2,c+2减1得到c+1,解引用得到"NEW"的首字符地址,再加1得到E的地址,最后%s输出EW