释放 C 中的动态字符串/行数组

Freeing array of dynamic strings / lines in C

我正在编写一个程序,用于对输入文本文件中的行进行排序。它完成了它的工作,但是我使用 valgrind 得到了内存泄漏。

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

char* getline(FILE * infile)
{
    int size = 1024;
    char * line = (char*)malloc(size);
    int temp;

    int i=0;
    do
    {
        (temp = fgetc(infile));
        if (temp !=EOF)
            line[i++]=(char)temp;
        if (i>=size)    
        {
            size*=2;
            line = (char*)realloc(line, size);
        }

    }while (temp != '\n' && temp !=EOF);
    if (temp==EOF)
        return NULL;
    return line;
}

void print_line (char * line)
{
    printf("%s", line);
}

int myCompare (const void * a, const void * b )
{
    const char *pa = *(const char**)a;
    const char *pb = *(const char**)b;

    return strcmp(pa,pb);
}

int main (int argc, char* argv[])
{
    FILE * infile;
    FILE * outfile;

    infile = fopen(argv[1], "r");
    if (infile==NULL)
    {
        printf("Error");
        exit(3);
    }
    outfile = fopen(argv[2], "w");
    if (outfile==NULL)
    {
        printf("Error");
        exit(3);
    }
    char * line;
    char **all_lines;
    int nlines=0;

    while((line=getline(infile))!=NULL)
    {
        print_line(line);
        nlines++;
    }

    all_lines=malloc(nlines*sizeof(char*));
    rewind(infile);
    int j=0;
    printf("%d\n\n", nlines);

    while((line=getline(infile))!=NULL)
    {

        all_lines[j]=line;
        j++;
    }

    qsort(all_lines, nlines, sizeof(char*), myCompare);

    for (int i=0; i<nlines;i++)
    {
        print_line(all_lines[i]);
        fprintf(outfile, "%s", all_lines[i]);
    }

    for(int i =0; i<nlines;i++)
    {
        free(all_lines[i]);
    }

    free(all_lines);
    fclose(infile);
    fclose(outfile);
    return 0;   
}

他们可能来自哪里的任何想法?我遍历 all_lines[] 并释放内容,然后释放 all_lines 本身。

更新:

好的,我已经完成了您建议的更新。但是,现在 valgrind 在我的程序中为函数 fprintf 抛出错误。这是它所说的:

11 errors in context 2 of 2:

==3646== Conditional jump or move depends on uninitialised value(s)
==3646==    at 0x40BA4B1: vfprintf (vfprintf.c:1601)
==3646==    by 0x40C0F7F: printf (printf.c:35)
==3646==    by 0x80487B8: print_line (sort_lines.c:44)
==3646==    by 0x804887D: main (sort_lines.c:77)
==3646==  Uninitialised value was created by a heap allocation
==3646==    at 0x4024D12: realloc (vg_replace_malloc.c:476)
==3646==    by 0x8048766: getline (sort_lines.c:30)
==3646==    by 0x804889A: main (sort_lines.c:75)

我想知道为什么它会在将这些行简单地 fprintf 到文本文件时报告错误。我查了一下这是关于 gcc 优化将 fprint 变成 fputs 但我不明白这个想法

您的代码中存在多个问题:

函数getline:

  • line 缓冲区中的字符串在 do / while 循环结束时未正确 '[=12=]' 终止。
  • 它不会 free 在文件结束时 line 缓冲区,因此 内存泄漏
  • 如果文件不以 '\n' 结束,它不会 return 在文件末尾的部分行。
  • mallocrealloc return 值均未检查内存分配失败。
  • 您应该realloc line 到实际使用的大小以减少消耗的内存量。目前,您每行至少分配 1024 个字节。对字典进行排序将需要 100 倍 的内存!

函数MyCompare:

读取的行在末尾包含 '\n'。比较可能会产生意想不到的结果:"Hello\tworld\n" 会出现在 "Hello\n" 之前。您应该删除 getline 中的 '\n' 并适当修改 printf 格式。

函数main:

  • 在尝试使用 fopen 打开它们之前,您没有检查是否实际提供了命令行参数,调用未定义的行为
  • 第一个计算行数的循环没有freegetline编辑的行return...大内存泄漏!
  • 输入流不能总是 rewinded。如果您的程序通过管道获得输入,rewind 将失败,除非输入非常小。
  • 如果文件被另一个进程异步修改,则第二个循环中读取的行数可能与第一个循环中计数的行数不同。如果文件变大,则在加载它时调用未定义的行为,如果文件缩小,则在对数组排序时调用未定义的行为。您应该在单个循环中读取行时重新分配 all_lines 数组。

在排序前打印行不是很有用并且会使测试复杂化。