为何char**未分配内存时调用strtok会段错误,char*[]则正常?
为什么code1会触发段错误?
这得先把char** savearr1的本质说透:它只是一个指向指针的指针,但你完全没给它分配任何有效的内存空间——说白了,savearr1现在就是个野指针,指向内存里的随机地址。
当你写savearr1[i]的时候,本质是在做*(savearr1 + i):从这个随机地址出发,偏移i * sizeof(char*)个字节去访问内存。这个地址既不属于你的程序,也没被系统分配给你,属于彻头彻尾的非法内存访问。
而strtok的第一个参数要求是指向可访问、可修改内存的指针(第一次调用时),你把savearr1[i]这个野指针传进去,strtok尝试读取或修改它指向的内存,直接触发操作系统的内存保护机制,也就是段错误。
code2为什么能执行成功?
再看char* savearr2[100]:这是一个固定大小的char*数组,如果是局部变量的话,它在栈上被预先分配了100个char*类型的存储空间。也就是说,savearr2[0]到savearr2[99]每个位置都是合法的内存地址——虽然初始值是随机的,但你可以安全地把strtok返回的子串指针赋值给这些位置。
我猜你实际的代码逻辑应该是这样的(修正了表述里可能的偏差):
char* token = strtok(path, "/"); int i = 0; while (token != NULL) { savearr2[i++] = token; token = strtok(NULL, "/"); }
因为savearr2本身有合法的内存空间来存储这些指针,所以整个过程不会触发内存错误。
char*[] 与 char** 的核心差异
这俩经常被新手混淆,但本质完全不同:
- 内存属性:
char* savearr2[100]是数组,内存是编译时分配的(局部变量在栈上,全局变量在静态区),大小固定,地址是编译时确定的。你可以直接访问它的元素,不需要手动分配内存。char** savearr1是指针变量,只占用一个指针大小的内存(比如64位系统是8字节),默认是野指针。必须手动通过malloc/calloc给它分配一块能存储多个char*的内存,比如savearr1 = malloc(100 * sizeof(char*));,之后才能像数组一样访问savearr1[i]。
- 灵活性与使用场景:
- 数组适合提前知道存储数量的场景,使用简单,但大小不能动态调整。
- 指针的指针适合需要动态扩展的场景,比如你不知道要分割出多少个子串,可以先分配一块初始内存,不够时再用
realloc扩容,但必须手动管理内存(用完要记得free)。
额外注意点
顺便提一句:strtok会直接修改原字符串(把分隔符替换成\0),你的path是malloc分配的可写内存,没问题;但如果是字符串字面量(比如char* path = "abc/def/ghi";),传进strtok会触发未定义行为,这点要留意。
内容的提问来源于stack exchange,提问作者mille

