C语言释放二维char指针数组报free(): invalid pointer错误排查
错误诱发原因
- 直接诱因是数组越界写入破坏了堆内存管理元数据:代码中为
arguments二级指针申请的堆空间大小为numOfArgs + 1个char*单位,按照C语言从0开始的下标规则,该数组的合法可写范围是下标0到下标numOfArgs。但代码中错误地将终止NULL写到了arguments[numOfArgs + 1]位置,该位置不属于申请的内存范围,写入操作会覆盖堆管理器用来维护内存块的私有元数据。 - 以测试用例为例:传入
numOfArgs=4时,实际申请了5个char*的空间(对应下标0~4),但NULL被写入下标5的位置,越界1个指针长度。后续调用free()释放堆块时,堆管理器校验元数据发现被篡改,直接抛出free(): invalid pointer错误,发送SIGABRT信号终止进程。 - 代码还存在额外隐患:没有校验
strtok()的返回值,如果实际分割出的参数个数小于传入的numOfArgs,strtok()会返回NULL,后续执行strlen(argument)会触发空指针访问崩溃。
修复方案
- 修正NULL终止符的写入位置,将
arguments[numOfArgs + 1] = NULL;修改为arguments[numOfArgs] = NULL;,匹配申请的数组长度,避免越界。 - 增加
strtok()返回值的空指针判断,当分割出的参数数量不足时提前终止循环,避免空指针访问。 - 完整释放内存时需要先遍历数组逐个释放每个参数的字符串内存,最后释放外层的指针数组本身,避免内存泄漏。
修正后的完整可运行代码如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #ifndef BUFSIZ #define BUFSIZ 1024 #endif char** getArguments(char* input, int numOfArgs) { char copy_arguments[BUFSIZ]; strcpy(copy_arguments, input); char** arguments = calloc(numOfArgs + 1, sizeof(char*)); if (arguments == NULL) { return NULL; } char* argument = NULL; for (int i = 0; i < numOfArgs; i++) { if (i == 0) { argument = strtok(copy_arguments, " "); } else { argument = strtok(NULL, " "); } // 处理分割参数不足的情况 if (argument == NULL) { arguments[i] = NULL; break; } int size_of_arg = strlen(argument); arguments[i] = calloc(size_of_arg + 1, sizeof(char)); strcpy(arguments[i], argument); } // 修正下标,写入正确的终止位置 arguments[numOfArgs] = NULL; return arguments; } int main() { char **output = getArguments("hello world -n vim", 4); // 此时释放单个元素不会触发内存错误 free(output[0]); output[0] = NULL; // 置空避免野指针 // 完整释放剩余内存 for (int i = 1; output[i] != NULL; i++) { free(output[i]); } free(output); return 0; }
内容的提问来源于stack exchange,提问作者mustafaHTP
相关产品推荐
相关产品推荐

