有这样一道面试题算不上难,但是如果出现了一时半刻也不容易算出正确的结果来,那仫就是很有必要了解一下的,代码详情如下:
char *c[]={"ENTER","NEW","POINT","FIRST"};
char **cp[]={c+3,c+2,c+1,c};
char ***cpp=cp;
int main()
{
printf("%s\n",**++cpp); //POINT
printf("%s\n",*--*++cpp+3); //ER
printf("%s\n",*cpp[-2]+3); //ST
printf("%s\n",cpp[-1][-1]+1); //EW
system("pause");
return 0;
}
刚一看到这道题我没有画出详细的指针指向关系图,所以很容易的猜出第一个printf的结果,但是当我继续计算后面的结果时我发现没有画出详细指向关系图的我此时已经凌乱了,到底现在的指针指向是是哪里呢?这就是我想提的第一个容易让人遗忘的点-当遇到这种指针指向复杂的题时一定要画出明确的关系图
画出详细的指向关系图之后,我们先来简单的分析一下c,cp,cpp到底是什仫?
在该代码中c就是一个简单的指针数组,是用来存储字符类型的指针的;cp是一个二级指针数组,用来指向一级指针数组c的;cpp就是一个三级指针,它里面存放的就是二级指针数组cp的地址;好了大概分析了c,cp,cpp是什仫之后下面就来讨论这四个表达式到底指向的是什仫?
**++cpp
我们知道不管是前置++还是后置++它都是存在后遗症的-加了之后就会改变指针本身的指向,而普通的加法则没有,这就是第二个容易遗忘的点
1).++cpp:在上面这道表达式中先执行++之后,三级指针cpp指向的是cp中c+2的位置
2).**++cpp:而两次解引用之后就是指针数组c中POINT的地址了,可以通过指针指向图查找
*--*++cpp+3
在执行了第一个表达式之后三级指针cpp指向的是c+2的位置
1).执行++cpp之后三级指针cpp指向的是c+1的位置
2).*++cpp:就是c+1这块空间的内容
3).--*++cpp:将c+1减1变为c,此时三级指针cpp依然指向原来c+1的这块空间
4).*--*++cpp:此时再次解引用就是指针数组c中ENTER的地址了
5).*--*++cpp+3:将该指针所指向的地址向后偏移3,此时指向的就是E的地址了,以%s的形式输出它也就是输出ER
*cpp[-2]+3
我们知道cpp是三级指针,其实不管是几级指针,它都可以用数组或者指针的形式来表达所要使用的空间;那仫我们就可以将*cpp[-2]+3等价为**(cpp-2)+3
1).cpp-2:第二个表达式执行完毕后cpp依然指向原来c+1的这块空间,cpp-2则使得我们找到的是存放c+3的这块空间,但是此时cpp指向的依然是c+1的这块空间
2).**(cpp-2):两次解引用使得我们找到指针数组c中指向RIRST这块空间的地址
3).**(cpp-2)+3:类似表达式2地址向后偏移3,此时指向的就是S的地址了,以%s的形式输出该地址也就是输出ST
cpp[-1][-1]+1
1).首先将cpp[-1][-1]等价为*(*(cpp-1)-1)+1,即使执行了表达式3,我们知道此时cpp依然指向的存放c+1的这块空间
2).*(cpp-1):此时我们找到的是c+2的这块空间,但是此时cpp依然指向的是c+1的这块空间,对减一之后的这块空间再解引用就是c+2这块空间的内容
3).*(*(cpp-1)-1):对c+2减1此时这块空间的内容由c+2变为c+1,再解引用,此时就是指针数组c中指向NEW这块空间的地址了
4).*(*(cpp-1)-1)+1:地址向后偏移1,此时指向的就是E的地址了,以%s的形式输出该地址也就是输出EW
那仫我们的分析是否正确呢?下面就来验证一下:
至此这道面试题分析完毕over