如何用Valgrind修复C语言中invalid write of size 1内存错误?
问题根源分析
Valgrind报的「invalid write of size 1」是数组越界写入导致的,同时代码还存在内存泄漏问题,核心问题拆解如下:
越界写入+内存泄漏的直接原因
- 代码先执行
v[0] = malloc(sizeof(char)*(longueur+2));分配了足够存带冒号的字符串空间,但紧接着用v[0] = strdup(strtok(s, " \n\t:"));覆盖了这个指针,导致之前malloc的内存直接丢失(内存泄漏)。 strdup会根据strtok返回的token长度分配内存(长度为token长度+1,用于存终止符)。如果原token长度是longueur,那么v[0]的可用索引范围是0到longueur(最后一位是'\0')。此时执行v[0][longueur] = ':'和v[0][longueur+1] = '\0',相当于写入了超出strdup分配的内存区域,触发越界写入错误。
- 代码先执行
其他潜在问题
- 函数参数
delim未被使用,硬编码了分隔符,违背函数设计意图。 - 第一次统计token数量时用的分隔符是
" \n\t:",但后续提取token时,循环阶段用的是" \n\t",可能导致nw的计数和实际提取的token数量不匹配,引发数组越界。
- 函数参数
修复方案
针对上述问题,调整代码逻辑确保内存分配正确且无越界:
char ** split(const char * str, const char * delim) { // 复制原字符串,避免修改输入 char * s = strdup(str); if (!s) return NULL; // 第一次遍历统计token数量,使用传入的delim参数 char * token = strtok(s, delim); if (!token) { free(s); return NULL; } int nw = 1; while (strtok(NULL, delim) != NULL) { nw++; } // 重置s为原字符串,准备第二次提取 strcpy(s, str); char ** v = malloc((nw + 1) * sizeof(char *)); if (!v) { free(s); return NULL; } int i = 0; // 提取第一个token token = strtok(s, delim); int token_len = strlen(token); // 检查原字符串对应位置是否有冒号 if (str[token_len] == ':') { // 分配足够存token+冒号+终止符的空间 v[0] = malloc(token_len + 2); if (!v[0]) { // 内存分配失败时清理已分配资源 while (i > 0) free(v[--i]); free(v); free(s); return NULL; } strcpy(v[0], token); v[0][token_len] = ':'; v[0][token_len + 1] = '\0'; } else { // 无冒号时直接复制token v[0] = strdup(token); if (!v[0]) { free(v); free(s); return NULL; } } // 提取剩余token for (i = 1; i < nw; ++i) { token = strtok(NULL, delim); v[i] = strdup(token); if (!v[i]) { // 内存分配失败时清理已分配资源 while (i > 0) free(v[--i]); free(v); free(s); return NULL; } } v[i] = NULL; // 标记数组结束 free(s); return v; }
关键修复点说明
- 修复越界写入:不再覆盖malloc的指针,而是根据是否需要添加冒号分别处理内存分配——需要冒号时分配
token_len+2的空间,确保有足够位置存冒号和终止符;不需要时直接用strdup。 - 解决内存泄漏:移除了无用的
malloc后覆盖指针的操作,同时添加了内存分配失败时的资源清理逻辑,避免泄漏。 - 统一分隔符:使用函数参数
delim替代硬编码的分隔符,符合函数设计预期;同时统计token和提取token时使用相同的分隔符,确保nw计数准确。 - 增加错误处理:对
malloc和strdup的返回值进行检查,避免空指针操作。
内容的提问来源于stack exchange,提问作者Mamoune Mouchtaki
相关产品推荐
相关产品推荐

