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

时间:2019-01-27 04:46:38

标签: 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;
}

1 个答案:

答案 0 :(得分:1)

关于第一次泄漏。在函数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),第一个结果是永远不会生成带有有效数据的头条目

事情从那里走下坡路。

请更正