今天看到一个巨变态和奇葩的C++题目,花了很久才弄懂为什么。手头书上的答案还有误,因此特意记录下来。
题目如下:
判断输出:
#include
int main()
{
char *str[]={"Welcome","to","Fortemedia","Nanjing"};
char **p=str+1;
str[0]=(*p++)+2;
str[1]=*(p+1);
str[2]=p[1]+3;
str[3]=p[0]+(str[2]-str[1]);
printf("str[0]=%s\n",str[0]);
printf("str[1]=%s\n",str[1]);
printf("str[2]=%s\n",str[2]);
printf("str[3]=%s\n",str[3]);
return 0;
}
在逐步分析之前先举个例子:
对于常规的指针来说,比如:
int b=1;
int* a=&b;
那么输出*a,是1;输出a,是b的地址。
但是,char*是个特殊的指针例子。比如:
char *str="this is a test";
这时候,输出*str,只会输出“t”;
输出str,显示的并不是地址,而是“this is a test”(完整的字符串)!
如果先执行str=str+2,那么输出str,会输出“is is a test”;输出*str,会输出“i”。
现在开始一句一句看上面的题目:
char *str[]={"Welcome","to","Fortemedia","Nanjing"};
char **p=str+1;
第一句*str[ ],定义的是一个指针数组,数组的名字叫str,每个元素是一个字符串指针;
第二句,**p=str+1,那么这个p,是一个指针,指向了另一个指向字符串的指针。
(这里隐含了一个重要的信息!即:p=&str[1];)
那么这时,*p指向的是“to”的首地址:
如果输出*p,输出的是“to”;
如果输出**p,输出的是“t”;
如果输出p[0],会输出“to”(p[0]就相当于*p了!这就好比数组a[10],输出*a其实就是a[0],一码事)
如果输出p[1],会输出“Fortemedia”
如果输出p[2],会输出“Nanjing”
然后:
str[0]=(*p++)+2;
这句话有个陷阱:
*p++究竟是“ (*p)++ ” 还是“ *(p++) ”?
查阅资料可知,++的优先级高于*,因此是p++(p自增),而不是(*p)++(不是*p自增)
因为是后置加法,返回的是未自增以前的p!
str[0]=(*p++)+2等同于:
1. str[0]=*p+2;(这里的p是自增以前的p,str[0]在加2前,指向“to”首地址,加完2,指向的是to中的第三位,即结尾符“\0”)
2. p=p+1;(同样隐含了一个重要信息:p=&str[2],这个之后会用到!!留意!;p此时指向了一个指向字符串"Fortemedia"的指针str[2])。
那么输出str[0],显示为空,其实是输出的“\0”。
ps:关于上面这个,我要说一点:有的辅导书上写的是错的,他们说,先p自增,跑到了Fortemedia这里,即str[2],然后又加了个2,跑到了str[4],而str[ ]数组只有1到3,str[4]是空,所以str[1]被赋值为空。
这纯粹是胡说八道。说明写书的人自己都不懂。如果不信,可以把上面的str换一下:
char *str[]={"Welcome","toa","Fortemedia","Nanjing"};(即把第二个to改成toa)
那么执行str[0]=(*p++)+2;输出str[0],不是空,而是a。
(符号优先级代表的是结合的优先级,而不是执行顺序。str[0]=(*p++)+2并不代表我要先把p++再取*再加2;而是意味着是p自增,而不是*p自增。实际上是先*再+2,最后p自增)
之后:
str[1]=*(p+1);
我们知道p已经指向了str[2]的地址,也就是指向了一个指向字符串"Fortemedia"的指针。p+1,是str[2]的地址加1,那么返回str[3]的地址,取*,得到指向“Nanjing”的指针,因此输出str[1],是“Nanjing”。
再之后:
str[2]=p[1]+3;
p此时指向一个指向Fortemedia的指针,p[0]则相当于是*p,是指向Fortemedia的指针。p[1]指向了最后的Nanjing字符串首地址。
p[1]+3,得到指向“jing”的首地址的指针,返回str[2]中。
注意到前面的重要信息,p=&str[2],str[2]改变了,p也随之改变,因此p指向了一个指向“jing”的指针。
事实上这句话与*p=p [1]+3等价。
输出str[2],结果为“jing”。
最后:
str[3]=p[0]+(str[2]-str[1]);
我们要知道,p[0]相当于是*p,是指向“jing”的指针;
str[2]也是指向“jing”,str[1]我们刚刚知道,指向“Nanjing”。
(str[2]-str[1])得到3。
p[0]指向jing的指针,再加3,指向了g,因此str[3]输出g。