утечка памяти при чтении файла в дважды связанный список - PullRequest
0 голосов
/ 27 января 2019

Пожалуйста, рассмотрите этот код, с которым я возился, он читает файл и загружает в двусвязный список:

#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 голосов
/ 27 января 2019

относительно первой утечки. в функции 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). Первый результат - НИКАКАЯ запись заголовка никогда не генерируется с действительными данными

Оттуда дела идут вниз.

Пожалуйста, исправьте

...