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

如何用Valgrind修复C语言中invalid write of size 1内存错误?

问题根源分析

Valgrind报的「invalid write of size 1」是数组越界写入导致的,同时代码还存在内存泄漏问题,核心问题拆解如下:

  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分配的内存区域,触发越界写入错误。
  2. 其他潜在问题

    • 函数参数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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 01:21:04