某日,有人问我一道题目,据说来自百度笔试,我也没去验证。先看如下一段代码:
void fun(void * str)
{
char* p = *(char **)str;
char * q = (char *)str;
}
问:p和q有什么区别?
这个题目蛮有趣的,主要考察c风格字符串和指针的相关知识。为了更清楚地分析问题,我们不妨写个主函数,测试一下函数fun:
int main()
{
char str[] = "abcde";
fun(str);
return 0;
}
char *q = (char *)str,相信大家对这句话都不会有疑问,如果打印q,会得到字符串"abcde"。
问题就出在char *p = *(char**)str这句话上。str首先被转换为char**类型,即指向指针的指针,也就是二级指针。说得浅显些,(char **)str存着一个地址,按照这个地址找过去,得到的应该是一个char指针。也就是说,str处存储的内容被编译器当成了一个地址——指向一个char指针的地址!那么,str处存储的是什么?没错,是一串连续的字符“abcde”!也就是说,一串连续字符被编译器当成了一个指向char指针的地址,这就是真相!
当然,对于32位机器来说,编译器只能将str所指的字符串的前4个字符abcd作为地址。我在linux下用g++编译这段代码,因此采用小端存储模式,即高位字节存于高地址,低位字节存于低地址。对于字符串“abcd”而言,d显然处于最高地址,而a处于最低地址,所以,如果把“abcd”作为一个整体读出来,d是最高位字节,a是最低位字节,其16进制形式应该是“0x64636261”,而非"0x61626364"。对(char**)str进行一次解引用,即*(char**)str,编译器就按照地址0x64636261去寻找,并找到一个char指针。如果幸运,这个char指针或许仍然可以作为一个字符串被读出;如果不幸运,例如,地址0x64636261本身就是一个应用程序不可达的位置,那么程序运行就会出现段错误了。