经典的指针试题,让你彻底理解指针
前言
之前对于指针做了一个详解,现在来看一些关于指针的经典面试题。
再次说一下数组名
数组名通常表示的都是首元素的地址,但是有两个意外,1.sizeof(数组名)这里数组名表示整个数组,计算的是整个数组大小。2.&数组名,这里的数组名表示的依然是整个数字,所以取地址取出的是整个数字的地址。注意:数组传参的本质是首元素的地址,所以形参访问的数组和实参的数组是同一个数组。
一、例题1(程序的结果是什么?)
include <stdio.h>
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,5
二、例题2(打印结果是什么?)
#include<stdio.h>
int mian()
{
int a[4]={1.2.3.4};
int*ptr1=(int*)(&a+1);
int*ptr2=(int*)((int)a+1);
printf("%X,%X",ptr[-1],*ptr2);
return 0;
}
这题跟第一题差不多,但是有变化,首先他还是先初始化了一个数字,然后取地址数组名在强制类型转换存到指针变量正确,然后这里有一个新的东西(int)a+1这个表示什么意思,a是一个整形一个整形是四个字节,这个+1就代表只前进一个字节的意思,举个例子
如果 a = oxoo12ff40 a+1-->ox0012ff44 (int)a+1-->ox0012ff41
这个题还要设计到一个大端小端的一个存储的问题,大端就是高到低低到高小端就是高到高,或者是低到低。
比如说小端存储 ox 00 00 01 这个01就是低地址,所以说就是这样放进去的 01 00 00 00 由低到高,低的放低,高的放高,这就是小端存储。
因为存在ptr2这种特殊状态,所以说我们要把它变成十六进制的存储方式
对ptr2解引用操作就是向后访问四个字节,从小端拿出0x 02 00 00 00 对ptr1解引用操作就是向后访问四个字节,从小端拿出就是0x 00 00 00 04。
三、例题3(打印结果是什么?)
include <stdio.h>
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;
}
注意:这个题实际上是存在一点问题的,因为这样强制把AP放在P里面会存在问题,他们的类型是不一样的,a的类型是int(*)[5],p的类型是int(*)[4]。
这个题难就难在一种思想就是类型不一样,该如何去思考,我们把二维数组直接看成一维数组来做,因为二维数组,其实他就是几个一维数组去构成的,我们把它排成一列,看成一维数组。&p[4][2]运用公式转换*(p+i)=p[i],*[*(p+4)+2]。然后我们在画的图上把P标出来就没问题了
*[*(p+4)+2]第一个解引用操作只拿到了数组名,意思就是说这进入了这个数组里,后面的+2就是在这个数组里加两个再借用就是拿到那个数字,他后面是取地址,就是说取到了那个地方的地址。然后就直接来数他们相差多少,很明显是-4,但是第一个是地址,我们就要把-4转换成补码的形式。用源反补的转化方式来转化。
10000000000000000000000000000100
111111111111111111111111111111111011
111111111111111111111111111111111100
FFFFFFFC
答案为oxFFFFFFFC,-4
四、例题4(打印结果是什么?)
#include <stdio.h>
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)这个直接用公式来变化为aa[1],所以就是数组名。二维数组的首元素是它第一行的地址,也就是一个一位数的地址
答案为10,5
五、例题5(打印结果是什么?)
#include <stdio.h>
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;
}
首先前置加加和后置加加会改变原来的值,所以不要++完还和原来的一样。这个题其实看上去很难,实际上就是一个连线题,把图画出来连线就可以了,首先要翻译题目的条件。*cpp[-2]+3等于*[*(cpp-2)+3],cpp[-1][-1]+1等于*[*(cpp-1)-1]+1。
先画出初始化的图
要按照顺序来连线因为,前置加加和后置加加会改变原来的值。
最开始cpp先加加再进行解引用,他最开始是指向的C +3开头的位置先加加就是只到了C +2,然后再对C +2进行解引用,所以说得到的就应该是POINT
第二问是解引用之后加加,然后最后再减减在加三,最后可以得到ER
第三问,我们已将问题化简*cpp[-2]+3等于*[*(cpp-2)+3],先减2解引用后在解引用加3,最后可得ST
最后一问,我们已将问题化简cpp[-1][-1]+1等于*[*(cpp-1)-1]+1,先减1在解引用后在减1解引用后在加一,最后可得EW。
答案为POINT,ER,ST,EW