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

C语言Shell解析管道命令时的内存泄漏问题排查

问题描述

我用C语言实现了一款最多支持20个管道(|)分隔命令的Shell,功能运行正常,但通过Valgrind进行内存检查时,发现split_commands函数中strdup存在24字节的明确内存泄漏。以下是Valgrind检测输出及相关代码:

Valgrind检测输出

==64422== HEAP SUMMARY:
==64422==     in use at exit: 24 bytes in 1 blocks
==64422==   total heap usage: 9 allocs, 13 frees, 4,156 bytes allocated
==64422== 
==64422== 24 bytes in 1 blocks are definitely lost in loss record 1 of 1
==64422==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==64422==    by 0x491260E: strdup (strdup.c:42)
==64422==    by 0x1098C5: split_commands (in /home/furkan/Masaüstü/hw02/my)
==64422==    by 0x109C93: main (in /home//Masaüstü/hw02/my)
==64422== 
==64422== LEAK SUMMARY:
==64422==    definitely lost: 24 bytes in 1 blocks
==64422==    indirectly lost: 0 bytes in 0 blocks
==64422==      possibly lost: 0 bytes in 0 blocks
==64422==    still reachable: 0 bytes in 0 blocks
==64422==         suppressed: 0 bytes in 0 blocks
==64422== 
==64422== For lists of detected and suppressed errors, rerun with: -s
==64422== ERROR SUMMARY: 11 errors from 8 contexts (suppressed: 0 from 0)

相关代码

char *strtrim(char *str) {
    char *end;

    // Trim leading space
    while (isspace(*str)) {
        str++;
    }

    if (*str == 0) {  // All spaces?
        return str;
    }

    // Trim trailing space
    end = str + strlen(str) - 1;
    while (end > str && isspace(*end)) {
        end--;
    }

    // Write new null terminator
    *(end+1) = 0;

    return str;
}

void split_commands(char *input, char **commands, int *num_commands) {
    int count = 0;
    const char delimiter[] = "|";
    char *token;
   

    // Count the number of commands
    for (int i = 0; input[i]!= '\0'; i++) {
        if(input[i] == '|')
           count++;
    }
    *num_commands = count + 1;

   

    // Split input into commands
    token = strtok(input, delimiter);
    for (int i = 0; i < *num_commands; i++) {
        (commands)[i] = strtrim(strdup(token));

        token = strtok(NULL, delimiter);
    }
}
泄漏原因排查

内存泄漏的核心原因是:split_commands函数中通过strdup为每个命令字符串分配了堆内存,但调用该函数的主程序中没有释放这些分配的内存块。

strdup内部会调用malloc分配内存并复制字符串,这些内存需要显式调用free释放。从代码来看,strtrim只是修改了strdup返回的字符串内容,并没有改变内存地址,因此commands[i]仍然持有strdup分配的内存指针,只要在合适时机释放即可。

解决方法

在主函数中,当不再需要commands数组中的命令字符串时,遍历数组逐个释放每个元素的内存:

// 假设num_commands是从split_commands获取的命令数量
for (int i = 0; i < num_commands; i++) {
    free(commands[i]);  // 释放每个strdup分配的内存
}

如果commands数组本身是通过malloc动态分配的(比如char **commands = malloc(sizeof(char*) * 21);),还要额外释放数组本身的内存:

free(commands);

注意:释放操作必须在commands数组不再被使用之后执行,避免出现野指针问题。

内容的提问来源于stack exchange,提问作者antonchekhov

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 18:04:58