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

C语言调用函数时动态分配的argv数组元素意外变更问题

问题根本原因

你遇到的是典型的栈局部变量生命周期结束导致的悬垂指针问题,属于C语言标准明确规定的未定义行为:

  • get_command函数中定义的input是栈上的局部变量,仅在get_command函数执行期间有效,函数返回后这块栈空间会被操作系统标记为可复用,不会保留原有内容。
  • 你用strtok拆分字符串得到的指针,全部指向input数组内部的地址,把这些地址赋值给argv元素后,argv[0]、argv[1]本质上就是指向已经失效的栈空间的悬垂指针。

异常表现的具体成因
  • get_command执行结束刚返回main时,被释放的栈空间还没有被其他操作覆盖,所以你第一次调用printf输出argv[0]时还能读到原始输入的内容,这完全是巧合。
  • 调用cd函数时,系统会为cd分配新的栈帧,你在cd中定义的char cwd[MAX_BUF]大小为4096字节,恰好复用了之前input数组占用的栈空间,哪怕你没有主动修改cwd的内容,函数调用过程中的寄存器压栈、printf参数入栈等操作也会覆盖原来input里存储的字符串,所以你访问argv[0]指向的地址时,读到的就是被修改后的垃圾值。
  • 如果你删掉cwd的声明,cd的栈帧很小,没有覆盖到原来input对应的栈空间,就会出现“运行正常”的假象,本质上还是未定义行为,换编译参数、换操作系统版本都可能再次出现异常。

修复方案

不要让argv的元素指向栈局部变量的地址,需要把拆分得到的字符串复制到生命周期更长的堆内存中,参考修改后的get_command实现:

void get_command(char *argv[]) {
    char input[MAX_BUF];
    fgets(input, sizeof(input), stdin);
    // 移除fgets读取到的末尾换行符
    input[strcspn(input, "\n")] = '\0';
    
    char *token = strtok(input, " ");
    int idx = 0;
    while (token != NULL && idx < MAX_ARGS - 1) {
        // 为每个参数单独分配堆内存存储内容
        argv[idx] = malloc(strlen(token) + 1);
        strcpy(argv[idx], token);
        token = strtok(NULL, " ");
        idx++;
    }
    argv[idx] = NULL;
}

注意程序退出前需要先逐个释放argv中每个元素的内存,再释放argv本身,避免内存泄漏。


内容的提问来源于stack exchange,提问作者BillTheKid

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 17:24:00