C内存泄漏,在while循环中结束

时间:2015-09-04 13:08:35

标签: c memory-leaks

我的程序有内存泄漏,但我想我找到了原因。我正在做的是使用concat函数将标准输入中的所有单词添加到一个字符串中。

这是一个功能:

Word* readWords(FILE *file) {
    char buffer[201]; 
    char* all_words_string = "";   
    Word* word_node_list = NULL;   

    char* cp = fgets(buffer, 201, file);
    while (cp != NULL) {   
        all_words_string = concat(all_words_string, cp); 
        cp = fgets(buffer, 201, file);
    } 
    char** word_list = wordList(all_words_string); //You can probably ignore this
    free(all_words_string);
    word_node_list = count_words(word_list); //Ignore this
    freeWordList(word_list); //Ignore this
    free(word_list); //Ignore this

   return word_node_list;
}

调用函数concat:

char* concat(char *s1, char *s2){
    char *result = malloc(strlen(s1)+strlen(s2)+1);
    strcpy(result, s1);
    strcat(result, s2);
    return result;
}

我认为while循环

    while (cp != NULL) {   
        all_words_string = concat(all_words_string, cp); 
        cp = fgets(buffer, 201, file);
    } 

负责我的内存泄漏。因为我在concat中分配了所有这些空间,然后删除指向它的指针,然后我只释放它的最后一个实例。

这是我内存泄漏的原因吗?如果是这样,我该如何解决?

4 个答案:

答案 0 :(得分:4)

您已正确分析问题。每个malloc()calloc()都应该与相应的free()配对,而您无法做到。您的代码也有一些其他的不足之处,例如无法检查错误条件的函数结果。

我建议您查看realloc(),这会显着缓解您的问题。就上述处方而言,它允许您避免在malloc()之前插入额外的free()来电。此外,它的行为将允许您在初始化all_words_string时避免一些轻微的怪异。例如:

Word *readWords(FILE *file) {
    char *all_words_string = NULL;  /* NULL, not "" */
    char *cp;
    /* ... */

    cp = fgets(buffer, 201, file);
    while (cp != NULL) {   
        all_words_string = concat(all_words_string, cp); 
        cp = fgets(buffer, 201, file);
    } 

    /* ... */

    free(all_words_string);

    /* ... */
}

char* concat(char *base, const char *to_add){
    /* when its first argument is NULL, realloc() works like malloc(): */
    char *result = realloc(base, strlen(base) + strlen(to_add) + 1);

    if (result != NULL) { /* realloc() (and malloc()) returns NULL on failure */
        /* no need to copy the original string */
        /* no need to free it, either */
        strcat(result, to_add);
    }
    return result;
}

答案 1 :(得分:3)

您需要将结果存储在新变量中,以便在分配新值之前释放旧变量。例如:

// Need to allocate an empty string dynamically so we can free it
// later on.
char* all_words_string = malloc(1);
all_word_string[0] = 0; 

...

char* tmp = concat(all_words_string, cp);
if (tmp != NULL && tmp != all_words_string) {
    free(all_words_string);
    all_words_string = tmp;
}

答案 2 :(得分:3)

当您正在寻找内存泄漏时,您需要计算mallocfree的数量,并确保它们匹配。

您可能会说在此代码中有一个malloc和一个free,这是真的。但是 - 你从循环中调用malloc

所以每次你绕过这个循环:

while (cp != NULL) {   
    all_words_string = concat(all_words_string, cp); 
    cp = fgets(buffer, 201, file);
} 
你打电话给malloc一次。当你弹出循环时,你已经完成了一个未指定数量的malloc(可能为零)并且没有释放。

然后你这样做:

自由(all_words_string);

所以你现在已经完成了1 free和0,1或者两个或更多malloc次。

第一个会导致崩溃(因为你正在释放一个不是malloc的字符串),第二个会很好,第三个会导致内存泄漏。

你需要编写更像这样的代码:

char *all_words_string = strdup("");
...
while (cp != NULL) {   
    char *tmp = concat(all_words_string, cp); 
    free(all_words_string);
    all_words_string = tmp;
    cp = fgets(buffer, 201, file);
} 
...
free(all_words_string)

答案 3 :(得分:1)

在进入时似乎每次都会造成泄漏:

char* concat(char *s1, char *s2){
    char *result = malloc(strlen(s1)+strlen(s2)+1);
    strcpy(result, s1);
    strcat(result, s2);
    return result;
}

不要在这里调用malloc而是考虑调用realloc。 替换下面的行

char * result = malloc(strlen(s1)+ strlen(s2)+1);

s1 = realloc(s1,(strlen(s1)+ strlen(s2)+1));

这应该负责动态释放先前分配的内存。