请求调试C语言代码及排查GCC运行后异常问题
嘿,我来帮你搞定这个问题!先拆代码里的错误,再解释为啥GCC执行后会崩。
先把你的代码贴出来,咱们逐行看问题:
#include<stdio.h> int main() { static char *s[] = {"black", "white", "pink", "violet"}; char **ptr[] = {s+3, s+2, s+1, s}, ***p; p=ptr; ++p; printf("the value of **p is %s\n\t",**p); // printed on screen pink printf("the value of **ptr[1] is %s\n\t",**ptr[1]); // here got the error printf("the value of *(s[2]) is %s\n\t",*s[2]); // here got the error return 0; }
第一个错误:**ptr[1]类型不匹配,踩了运算符优先级的坑
C语言里[]的优先级比*高,所以ptr[1]会先被计算。ptr是char **类型的数组,ptr[1]对应的是s+2——也就是指向"pink"的指针(属于char **类型)。
你写的**ptr[1],实际执行顺序是*( *(ptr[1]) ):
- 第一层
*ptr[1]拿到的是"pink"的首地址(char *类型); - 第二层
*就会取这个地址的第一个字符,也就是'p'(单个char类型)。
但printf的%s格式符需要的是字符串的首地址(char *类型),你传了个单个字符,程序会把这个字符的ASCII值(比如'p'是112)当成内存地址去访问,这属于非法内存操作,直接就崩了。
修复方法:把**ptr[1]改成*ptr[1],这样就拿到了正确的字符串指针。
第二个错误:*s[2]同样是类型不匹配
s是char *类型的数组,s[2]本身就是指向"pink"的char *指针。*s[2]取的是这个指针指向的第一个字符'p'(还是单个char),同样不符合%s的要求,导致和上面一样的崩溃问题。
修复方法:把*s[2]改成s[2](或者*(s+2),效果完全一样),直接传入字符串的首地址就行。
修复后的完整代码
#include<stdio.h> int main() { static char *s[] = {"black", "white", "pink", "violet"}; char **ptr[] = {s+3, s+2, s+1, s}, ***p; p=ptr; ++p; printf("the value of **p is %s\n\t",**p); // printed on screen pink printf("the value of *ptr[1] is %s\n\t",*ptr[1]); // 修复后 printf("the value of s[2] is %s\n\t",s[2]); // 修复后 return 0; }
你遇到的执行异常,本质就是上面说的类型不匹配导致的未定义行为。C语言对这种情况,编译器可能不会直接报错(但如果你编译时加上-Wall参数,GCC会弹出警告:“format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’”),但运行时会触发段错误(Segmentation Fault),也就是非法访问内存,程序直接中途停止。
建议以后编译代码时加上-Wall -Wextra,让GCC帮你提前揪出这类潜在的错误,省得跑起来崩了才找问题。
内容的提问来源于stack exchange,提问作者Mohammed Kandeel

