void指针转char**触发段错误,转char*却正常?求解析
嘿,这个问题我之前也碰到过,本质就是指针层级不匹配导致的非法内存访问,咱们一步步拆解:
1. 为啥转char*时能正常跑?
假设你是这么调用compareStrings的:
char *str1 = "hello"; char *str2 = "world"; compareStrings(str1, str2);
这时候传给函数的两个void*参数,实际指向的是字符串的第一个字符(毕竟str1本身就是char*,指向char类型)。你把void*转成char*后,直接用strcmp比较,相当于直接对比两个字符串的内容,完全对应上了,所以没毛病。
2. 转char**触发段错误的核心原因
如果你还是用上面的调用方式(传入char*),却硬把void*转成char**,比如写了这种代码:
int compareStrings(const void *a, const void *b) { return strcmp(*(char**)a, *(char**)b); // 这里错了! }
问题出在指针层级乱了:
a原本是指向char的指针(因为传入的是str1,也就是字符串首地址),你强行把它转成char**(这是指向char*的指针),然后解引用*(char**)a,相当于把字符串的前4/8个字节(看你系统是32还是64位)当成一个char*的地址,去访问这个地址的内容。- 这个“凑出来”的地址基本都是非法内存(比如"hello"的前几个字节是
0x68656c6c,这绝对不是有效的内存地址),操作系统直接给你抛段错误,完全合理。
什么时候该用char**转换?
最常见的场景是用qsort排序字符串数组的时候,比如:
char *fruit[] = {"banana", "apple", "cherry"}; qsort(fruit, sizeof(fruit)/sizeof(fruit[0]), sizeof(char*), compareStrings);
这时候qsort传给compareStrings的a和b,是数组元素的地址——数组元素是char*,所以a实际是char**类型。这时候正确的写法应该是:
int compareStrings(const void *a, const void *b) { // 先转成const char**,再解引用拿到真正的字符串指针 const char *str1 = *(const char**)a; const char *str2 = *(const char**)b; return strcmp(str1, str2); }
这时候转换和解引用完全匹配实际的内存结构,就不会出问题了。
一句话总结
转char*正常,是因为你的调用参数和转换后的指针层级对得上;转char**崩了,是因为你传入的参数还是char*,但硬转成了更高层级的指针,解引用后踩了非法内存。要想用char**转换,必须保证传入的void*实际指向的是char*类型的变量(比如字符串数组的元素地址)。
内容的提问来源于stack exchange,提问作者greenwithe
相关产品推荐
相关产品推荐

