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

C语言读取文件转二维数组时出现内存泄漏,求排查修复

内存泄漏排查与修复方案

常见泄漏点分析

结合你的场景和Valgrind报告,大概率是以下问题导致泄漏:

  • 未释放getline分配的每行临时内存
  • 二维数组(char **)本身未被回收
  • 内存分配失败时未清理已分配的资源
  • 文件操作异常后未处理残留内存

修复后的完整代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

// 自行实现的realloc
void *my_realloc(void *ptr, size_t old_size, size_t new_size) {
    if (new_size == 0) {
        free(ptr);
        return NULL;
    }
    void *new_ptr = malloc(new_size);
    if (!new_ptr) return NULL;
    
    if (ptr && old_size > 0) {
        size_t copy_len = old_size < new_size ? old_size : new_size;
        memcpy(new_ptr, ptr, copy_len);
        free(ptr);
    }
    return new_ptr;
}

char **load_file(const char *filename, size_t *out_line_count) {
    FILE *fp = fopen(filename, "r");
    if (!fp) {
        perror("fopen failed");
        return NULL;
    }

    char **lines = NULL;
    size_t line_count = 0;
    char *line = NULL;
    size_t len = 0;
    ssize_t read_len;

    while ((read_len = getline(&line, &len, fp)) != -1) {
        // 可选:去除换行符
        if (read_len > 0 && line[read_len - 1] == '\n') {
            line[read_len - 1] = '\0';
        }

        // 扩展二维数组空间
        char **temp_lines = my_realloc(lines, line_count * sizeof(char *), (line_count + 1) * sizeof(char *));
        if (!temp_lines) {
            perror("realloc failed");
            // 清理已分配的所有内存
            for (size_t i = 0; i < line_count; i++) free(lines[i]);
            free(lines);
            free(line);
            fclose(fp);
            return NULL;
        }
        lines = temp_lines;

        // 独立分配每行内存,避免复用getline的临时指针
        lines[line_count] = malloc(strlen(line) + 1);
        if (!lines[line_count]) {
            perror("malloc line failed");
            for (size_t i = 0; i < line_count; i++) free(lines[i]);
            free(lines);
            free(line);
            fclose(fp);
            return NULL;
        }
        strcpy(lines[line_count], line);
        line_count++;
    }

    // 释放getline分配的最后一块临时内存
    free(line);
    fclose(fp);

    // 添加终止NULL指针,方便后续遍历
    char **final_lines = my_realloc(lines, line_count * sizeof(char *), (line_count + 1) * sizeof(char *));
    if (final_lines) {
        lines = final_lines;
        lines[line_count] = NULL;
    }

    if (out_line_count) *out_line_count = line_count;
    return lines;
}

// 专用内存释放函数
void free_lines(char **lines) {
    if (!lines) return;
    for (size_t i = 0; lines[i]; i++) free(lines[i]);
    free(lines);
}

int main() {
    size_t line_count;
    char **lines = load_file("test.txt", &line_count);
    if (!lines) return 1;

    // 测试输出(可选)
    for (size_t i = 0; i < line_count; i++) {
        printf("Line %zu: %s\n", i, lines[i]);
    }

    // 释放所有内存
    free_lines(lines);
    return 0;
}

关键修复点说明

  • 独立分配每行内存:不再直接存储getline返回的指针,而是复制到新分配的内存中,避免getline复用指针导致的内存管理混乱。
  • 错误时的全量清理:内存分配失败时,遍历释放已分配的所有行内存和二维数组,彻底避免泄漏。
  • 回收getline临时内存:循环结束后必须调用free(line),即使最后一次读取失败,getline也可能已分配内存。
  • 专用释放函数:free_lines负责遍历释放每行内存,最后回收二维数组,确保所有分配的资源都被回收。
  • 添加终止NULL指针:方便后续遍历判断结束,同时保证二维数组的结构完整性。

Valgrind验证效果

修复后运行Valgrind检测,应显示无明确泄漏:

==xxxx== LEAK SUMMARY:
==xxxx==    definitely lost: 0 bytes in 0 blocks
==xxxx==    indirectly lost: 0 bytes in 0 blocks
==xxxx==      possibly lost: 0 bytes in 0 blocks
==xxxx==    still reachable: 0 bytes in 0 blocks
==xxxx==         suppressed: 0 bytes in 0 blocks

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 21:41:10