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
相关产品推荐
相关产品推荐

