简体   繁体   English

如何在我的 C 程序中防止当前的 memory 泄漏?

[英]How can I prevent the current memory leaks in my C program?

I have a program where I load data from a text file into an array of structs.我有一个程序,我将文本文件中的数据加载到结构数组中。 My struct looks like this:我的结构如下所示:

typedef struct A {
    int id;
    char* name;
    char* desc;
} A;

I start loading the file from my main function:我开始从我的主 function 加载文件:

int main(void) {
    A* a;
    int* length = 0;
    arr = betolt("name.txt", &length);
    ...
    free(arr);

    return 0;
}

Then - in a different header file - the real logic happens like this:然后 - 在不同的 header 文件中 - 真正的逻辑是这样发生的:

A* load(char* file_name, int* length) {
    FILE* fp = fopen(file_name, "r");
    if (fp == NULL) return NULL;
    size_t ar_length = 500;
    size_t line_counter = 0;
    char** lines = malloc(ar_length);
    char line[256];
    while (fgets(line, sizeof(line), fp)) {
        lines[line_counter] = malloc(256);
        strcpy(lines[line_counter], line);
        line_counter++;
        if(line_counter > sizeof(lines)){
            ar_length *= 2;
            lines = realloc(lines, ar_length);
        }
    }
    *length = line_counter;
    fclose(fp);
    return process(lines, line_counter);
}

A* process(char** lines, int length) {
    A* arr = (A*) malloc(length * sizeof(A));
    for (int i = 0; i < length; ++i) {
        char* line = lines[i];
        char* ptr = strtok(line, ";");
        A a;
        a.id = i;
        int j = 0;
        while (ptr != NULL) {
            if (j == 0) {
                a.name = ptr;
            } else if (j == 1) {
                a.desc = ptr;
            }
            j++;
            ptr = strtok(NULL, ";");
        }
        arr[i] = a;
    }
    return arr;
}

My program works just fine, however, I got memory leaks for each loaded line because of the malloc(256) , and I also got memory leak after using realloc(lines, ar_length);我的程序工作得很好,但是,由于malloc(256)的原因,每条加载的行都有 memory 泄漏,并且在使用realloc(lines, ar_length); I'm quite unsure why I get these leaks because isn't it supposed to "automatically free" the memory after a function runs?我很不确定为什么会出现这些泄漏,因为它不应该在 function 运行后“自动释放” memory 吗? How can I fix these memory leaks?如何修复这些 memory 泄漏? Thanks in advance.提前致谢。

There are several general problems with your code.您的代码存在几个一般性问题。

  1. Casting result of malloc is considered a bad practice. malloc 的铸造结果被认为是不好的做法。 See this for details.有关详细信息,请参阅
  2. Realloc can fail and return NULL without freeing the original pointer, you are not taking it into consideration. Realloc 可能会失败并返回 NULL 而不释放原始指针,您没有考虑到它。 A better way would be +- this:更好的方法是 +- 这个:
int* x = malloc(200*sizeof(int));
//whatever
int* bigger_x = realloc(x, 400*sizeof(int));
if(bigger_x) x = bigger_x;
else handle_error("realloc");

As for points more specific to your question and problems:至于更具体到您的问题和问题的要点:

  1. I'm quite unsure why I get these leaks because isn't it supposed to "automatically free" the memory after a function runs?我很不确定为什么会出现这些泄漏,因为它不应该在 function 运行后“自动释放” memory 吗? How can I fix these memory leaks?如何修复这些 memory 泄漏?

No, it's not.不,这不对。 Generally you should clean up the used memory once you're done with using it.一般来说,一旦你完成使用它,你应该清理使用过的 memory。 When?什么时候? Good question;) Note, that you're using pointers to the dynamically allocated array, eg here: a.desc = ptr;好问题;)请注意,您正在使用指向动态分配数组的指针,例如: a.desc = ptr; . . A trivial solution would be to str ing dup licate each of those string, ie a.desc = strdup(ptr);一个简单的解决方案是复制每个字符串,即a.desc = strdup a.desc = strdup(ptr); , then free lines after process() returns. , 然后process()返回后的空闲lines Note, that you strdup actually does allocate, so you need to release the resources allocated by it once you're done with them.请注意,您的strdup实际上确实分配了,因此您需要在使用完它们后释放它分配的资源。

  1. Use valgrind or address sanitizer.使用 valgrind 或地址消毒剂。 Simply compile with debug symbols and -fsanitize=address , that will give you plenty of info of what and where is leaking.只需使用调试符号和-fsanitize=address进行编译,这将为您提供大量有关泄漏内容和位置的信息。 Conteporary version of clang and gcc support it. clang 和 gcc 的现代版本支持它。 Valgrind is also a way to go, but it's way less convenient imho. Valgrind 也是 go 的一种方式,但恕我直言,它不太方便。

Bonus point: C does not have RAII, but you can utilize some basic "scope guard" techniques anyway.加分项:C 没有 RAII,但无论如何您都可以使用一些基本的“范围保护”技术。 Consider the following code:考虑以下代码:

char* buffer = malloc(300);
if(buffer) {
//do whatever
}
free(buffer);

Should you forget about free() at the end, you'll have a memleak.如果你最后忘记了free() ,你就会有一个 memleak。 What you can do instead is use for loop in slightly creative way to introduce a "scope guard":您可以做的是以稍微有创意的方式使用 for 循环来引入“范围保护”:

for(char* buffer = malloc(300); buffer; free(buffer), buffer=NULL)
{
  //do stuff
}

Similar technique should also works for FILE* and other resources or can be generalized using macros, it's for you to decide whether you like it or not.类似的技术也应该适用于FILE*和其他资源,或者可以使用宏进行概括,由您决定是否喜欢。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM