c - 将文件读取到双向链表时泄漏内存

标签 c memory-leaks valgrind

请考虑我正在修改的这段代码,它读取文件并加载到双向链表中:

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

struct Node{
        char * data;
        struct Node *Next;
        struct Node *Prev;
};

struct Doubly_Linked_List{
        struct Node *headNode;
        struct Node *tailNode;
        int LLSize;
};

void InsertAtEnd(struct Doubly_Linked_List *myll, char* data );
void reBalance(struct Doubly_Linked_List *myll);
void PrintLL(struct Doubly_Linked_List *myll);
void append( struct Doubly_Linked_List *myll, char* data);

void PrintLL(struct Doubly_Linked_List *myll){
        struct Node *Node = myll->headNode;
        int i = 0;
        while (Node){
        //printf("Node is likely at %ld\n", Node->data);
                printf("Index: %d has : %s", i, Node->data);
                i++;
                Node = Node->Next;
        }

}

void reBalance(struct Doubly_Linked_List *myll){
        printf("Rebalancing myll\n");
        struct Node *Node = myll->headNode;
        struct Node *LastNode;
        int i = 0;
        while (Node){
                LastNode = Node;
                i++;
                Node = Node->Next;
        }
        myll->LLSize = i;
        myll->tailNode = LastNode;
}


void append( struct Doubly_Linked_List *myll, char* data){
        if (!myll->headNode){
        printf("Inserting at start\n");
                struct Node *NewHeadNode = malloc( sizeof(*NewHeadNode) ) ;
                NewHeadNode->data = malloc( strlen(data) * sizeof(char)  );
                strcpy(NewHeadNode->data, data);
                NewHeadNode->Prev = NULL;
                NewHeadNode->Next = NULL;
                myll->headNode = NewHeadNode;
        } else {
        printf("Inserting at end\n");
                InsertAtEnd(myll, data);
        }
}


void InsertAtEnd(struct Doubly_Linked_List *myll, char* data ){
        //printf("%s was evoked\n", __func__);
        reBalance(myll);
        struct Node *Node = myll->tailNode;
        struct Node *NewTailNode = malloc( sizeof(*NewTailNode) );
        NewTailNode->data = malloc( strlen(data) *sizeof(char) );
        strcpy(NewTailNode->data, data);
        NewTailNode->Next = NULL;
        NewTailNode->Prev = Node;
        Node->Next = NewTailNode;
        reBalance(myll);
}



void FreeMem(struct Doubly_Linked_List *myll){
        //printf("%s was evoked\n", __func__);
        reBalance(myll);
        int i = 0;
        struct Node *Node = myll->headNode;
        while (Node){
        struct Node *NextNode = Node->Next;
                //printf("Freeing Node at Index: %d with data : %s\n", i, Node->data);
        free(Node);
                i++;
                Node = NextNode;
        }
    free(myll);
}

int main(){

    char *filename = "/proc/net/dev";
    struct Doubly_Linked_List *myll = malloc(sizeof(myll));

    FILE *fp = fopen(filename,"r");
    if (!fp){
        printf("Error!\n");
        return 0;
    }

    char filetext[400];
    while (fgets(filetext, 400, fp) ){
        append(myll, filetext);
        PrintLL(myll);
        printf("myll->LLSize: %d\n", myll->LLSize);
    }

    fclose(fp);
    FreeMem(myll);
    return 0;
}

它工作正常,就像它枚举并打印链接列表一样,这看起来像它被要求读取的文件。

但是,valgrind 似乎表明我有内存泄漏:

==7755== 77 bytes in 1 blocks are definitely lost in loss record 1 of 2
==7755==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7755==    by 0x1089FE: append (stack_overflow.c:53)
==7755==    by 0x108BF7: main (stack_overflow.c:108)
==7755== 
==7755== 494 bytes in 4 blocks are definitely lost in loss record 2 of 2
==7755==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7755==    by 0x108AAF: InsertAtEnd (stack_overflow.c:70)
==7755==    by 0x108A62: append (stack_overflow.c:60)
==7755==    by 0x108BF7: main (stack_overflow.c:108)
==7755== 
==7755== LEAK SUMMARY:
==7755==    definitely lost: 571 bytes in 5 blocks
==7755==    indirectly lost: 0 bytes in 0 blocks
==7755==      possibly lost: 0 bytes in 0 blocks
==7755==    still reachable: 0 bytes in 0 blocks
==7755==         suppressed: 0 bytes in 0 blocks
==7755==

在烧了几个小时之后,它仍然在泄漏 - 571 字节是我能泄漏的最好的。我一定是在做一些我没有注意到的事情,并且想要另一双眼睛和指导。谢谢!

更新:1

谢谢!我根据回复和建议做了一些更改:切换到 calloc,并确保释放我从文件中读取的文本数据。

很高兴报告 valgrind 检查通过了:

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

struct Node{
        char * data;
        struct Node *Next;
        struct Node *Prev;
};

struct Doubly_Linked_List{
        struct Node *headNode;
        struct Node *tailNode;
        int LLSize;
};

void PrintLL(struct Doubly_Linked_List *myll);
void append( struct Doubly_Linked_List *myll, char* data);

void PrintLL(struct Doubly_Linked_List *myll){
        //printf("%s was evoked\n", __func__);
        struct Node *Node = myll->headNode;
        int i = 0;
        while (Node){
        //printf("Node is likely at %ld\n", Node->data);
                printf("Index: %d has : %s", i, Node->data);
                i++;
                Node = Node->Next;
        }
    printf("-----------------------------\n");

}

void Freemem(struct Doubly_Linked_List *myll){
    struct Node *Node = myll->headNode;
    while (Node){
        struct Node *Next = Node->Next;

        free(Node->data);
        free(Node);
        Node = Next;
    }
    free(myll);
}


void append( struct Doubly_Linked_List *myll, char* data){
        if (!myll->LLSize){
        printf("Inserting at start\n");
                struct Node *NewHeadNode = calloc(5, sizeof(*NewHeadNode) ) ;
                NewHeadNode->data = calloc( 1,( strlen(data) +2) );
                strcpy(NewHeadNode->data, data);
                myll->headNode = NewHeadNode;
                myll->tailNode = NewHeadNode;
        myll->LLSize = 1;
        } else {
        //printf("Inserting at end\n");
        struct Node *OldTail =  myll->tailNode;
        struct Node *NewTailNode = calloc(1, sizeof(*NewTailNode) );
        NewTailNode->data = calloc( 1,( strlen(data) +2) );
                strcpy(NewTailNode->data, data);

        // wire the pointers
        OldTail->Next = NewTailNode;
        NewTailNode->Prev = OldTail;
        NewTailNode->Next = NULL;

        // adjust our size
        myll->LLSize++;

        // set new tail node:
                myll->tailNode = NewTailNode;;
        }
}


int main(){

    char *nic = "wlp4s0";
    char *filename = "/proc/net/dev";

    struct Doubly_Linked_List *myll = calloc(10,sizeof(myll));

    FILE *fp = fopen(filename,"r");
    if (!fp){
        Freemem(myll);
        perror("Error!\n");
        return 1;
    }

    char filetext[400];
    while (fgets(filetext, 400, fp) ){
        append(myll, filetext);
        PrintLL(myll);
        printf("myll->LLSize: %d\n", myll->LLSize);
    }
    fclose(fp);

    Freemem(myll);
    return 0;
}

最佳答案

关于第一次泄漏。在函数 main() 中,在此代码块中:

if (!fp)
{
    printf("Error!\n");
    return 0;
}

此时代码执行中,对malloc()的调用已经执行完毕,因此分配的内存需要传递给free()

作为替代方案,在以下语句之后才调用 malloc():

char filetext[400];

在函数:append()中有一个检查:

if (!myll->headNode){

但是,当从 main() 调用时,数组 myll 尚未初始化为任何内容。第一个(未初始化)字段包含全部 0x00 的可能性很小。

您可能会尝试调用calloc(),而不是第一次调用malloc()(calloc将所有分配的内存设置为全部0x00)第一个结果是NO head条目始终使用有效数据生成

事情从那里开始走下坡路。

请更正

关于c - 将文件读取到双向链表时泄漏内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54385157/

相关文章:

c - 在链表中是否有必要命名所有单个节点?

c - 是什么阻止了 GCC __restrict__ 限定词的工作

c++ - C++ (windows) 中的分配数及其可预测性

iphone - iPad 应用程序中的内存问题

c - 存储在 EEPROM 中的数据结构的卷影副本

c - 如何使用 fscanf 读取文件

java - 一个演示Java内存泄漏的简单程序

c++ - 试图理解 valgrind 输出

c++ - c++ : valgrind leak 中的动态数组

c++ - 在 C++ 中跟踪函数调用的方法