You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 03:36:46