结构体返回值丢失问题:makeValidInstructions函数异常排查
问题分析与修复方案
我来帮你拆解下问题所在,你遇到的两个现象(第一次打印正常、第二次失效)其实对应两个不同的核心问题:
1. 第二次打印失效的直接原因
你第二次打印时访问的索引已经越界指向未初始化的元素了!
看这段代码的执行顺序:
// 第一次打印:此时validInstructionIndex指向刚存入的元素,没问题 printf("ADDED %i %s", validInstructionIndex, validInstructions[validInstructionIndex].arguments[0]); validInstructionIndex++; // 索引自增,指向了下一个空位置 // 第二次打印:你用了自增后的索引,访问的是未赋值的数组元素 printf("ADDED %i %s", validInstructionIndex, validInstructions[validInstructionIndex].arguments[0]);
修复这个很简单,第二次打印时用validInstructionIndex - 1访问刚添加的元素即可。
2. 结构体存入数组的深层问题:浅拷贝导致野指针
你处理arguments的方式存在内存安全问题:
instruction_t中的arguments是char**类型,当你执行validInstructions[validInstructionIndex] = tempInstruction时,这是浅拷贝——两个结构体的arguments指针会指向同一块内存。- 如果
makeValidInstructions函数里的arguments是分配在栈上的临时内存,那么当tempInstruction的生命周期结束后,validInstructions里的arguments就会变成野指针,后续访问必然出问题。 - 你写的
strcpy(*validInstructions[...].arguments, ...)只复制了第一个参数的字符串,并没有处理所有参数,这也会导致后续访问其他参数时出错。
修复方案:实现arguments的深拷贝
需要为validInstructions中的每个instruction_t单独分配内存,逐个复制参数字符串:
if (tempInstruction.initializedProperly) { if (validInstructionIndex < MAX_NUMBER_OF_COMMANDS) { int argCount = supportedCommands[j].argc; // 确认该命令的参数总数(包括命令名) instruction_t* dest = &validInstructions[validInstructionIndex]; // 复制基础字段 dest->id = tempInstruction.id; dest->initializedProperly = true; // 为arguments指针数组分配内存(+1用于存储NULL终止符) dest->arguments = malloc(sizeof(char*) * (argCount + 1)); if (dest->arguments == NULL) { fprintf(stderr, "ERROR - Failed to allocate memory for arguments"); dest->initializedProperly = false; continue; } // 逐个复制每个参数字符串 bool copySuccess = true; for (int k = 0; k < argCount; k++) { dest->arguments[k] = strdup(tempInstruction.arguments[k]); if (dest->arguments[k] == NULL) { fprintf(stderr, "ERROR - Failed to copy argument %d", k); // 回滚已分配的内存,避免泄漏 for (int m = 0; m < k; m++) free(dest->arguments[m]); free(dest->arguments); dest->arguments = NULL; dest->initializedProperly = false; copySuccess = false; break; } } if (copySuccess) { dest->arguments[argCount] = NULL; // 添加终止符,和argv格式一致 // 第一次打印(正常) printf("ADDED %i %s", validInstructionIndex, dest->arguments[0]); validInstructionIndex++; // 第二次打印修复后 printf("ADDED %i %s", validInstructionIndex - 1, validInstructions[validInstructionIndex - 1].arguments[0]); } } else { fprintf(stderr, "ERROR - Max limit of commands exceeded! There can be no more than %i commands at a time", MAX_NUMBER_OF_COMMANDS); } }
额外注意事项
- 记得在程序结束或不再使用
validInstructions时,遍历数组释放内存:for (int k = 0; k < validInstructionIndex; k++) { if (validInstructions[k].arguments != NULL) { for (int m = 0; validInstructions[k].arguments[m] != NULL; m++) { free(validInstructions[k].arguments[m]); } free(validInstructions[k].arguments); } } - 确认
makeValidInstructions函数中arguments的内存分配方式,如果是堆内存,要注意避免重复释放;如果是栈内存,必须用深拷贝(如上代码)。
内容的提问来源于stack exchange,提问作者Desfell
相关产品推荐
相关产品推荐

