简体   繁体   English

如何在我的链表实现中修复此内存泄漏?

[英]How can I fix this memoryleak in my implementaion of linked list?

I compiled the code with the following command:我使用以下命令编译了代码:

gcc -std=c11 -Wall -Wextra -pedantic -fsanitize=address,undefined -o OUTFILE listen.c gcc -std=c11 -Wall -Wextra -pedantic -fsanitize=address,undefined -o OUTFILE listen.c

The only important functions in the source code is deqeue where the memory should be deallocated and enqeue where the memory is allocated.源代码中唯一重要的功能是在memory应该被释放的地方出队和在memory被分配的地方入队。

I have used a debugger to see where the error is (see pictures below), and I think that the function "dequeue" does not free the memory from the heap, which was used for the entries of my list.我使用调试器查看错误在哪里(见下图),我认为 function “dequeue”不会从堆中释放 memory,该堆用于我的列表条目。 But I don't know why the memory is not deallocated again.但我不知道为什么 memory 没有再次释放。 The variable curr is a pointer to the entry that has to be deleted, the memory adress does not change during the runtime after the free function is called.变量 curr 是指向必须删除的条目的指针,在调用空闲 function 后,memory 地址在运行时不会改变。

In the output a runtime error occured, memory was leaked:在 output 出现运行时错误,memory 被泄露:

>>> Test ob die Studentenliste leer ist ...
    Die Studentenliste ist leer 
>>> Fuege neuen Studenten in die Liste ein: Eddard Stark [1234] ...
    Matrikelnummer 1234 eingefügt
>>> Test, ob die Matrikelnummer 1234 bereits erfasst wurde ...
    Matrikelnummer 1234: Eddard Stark
>>> Fuege neuen Studenten in die Liste ein: Jon Snow [5678] ...
    Matrikelnummer 5678 eingefügt
>>> Test, ob die Matrikelnummer 1234 bereits erfasst wurde ...
    Matrikelnummer 1234: Eddard Stark
>>> Fuege neuen Studenten in die Liste ein: Tyrion Lannister [9999] ...
    Matrikelnummer 9999 eingefügt
>>> Test, ob die Matrikelnummer 1235 bereits erfasst wurde ...
    Matrikelnummer 1235 ist unbekannt
>>> Fuege neuen Studenten in die Liste ein: Daenerys Targaryen [1289] ...
    Matrikelnummer 1289 eingefügt
>>> Loesche die Matrikelnummer 1234 ...
    Matrikelnummer 1234 geloescht
>>> Test ob die Studentenliste leer ist ...
    Die Studentenliste ist leer 
>>> Test, ob die Matrikelnummer 5678 bereits erfasst wurde ...
    Matrikelnummer 5678 ist unbekannt
>>> Loesche die Matrikelnummer 9998 ...
    Matrikelnummer 9998 war nicht erfasst
>>> Fuege neuen Studenten in die Liste ein: Viserys Targaryen [1289] ...
    Matrikelnummer 1289 eingefügt
>>> Loesche die Matrikelnummer 5678 ...
    Matrikelnummer 5678 war nicht erfasst
>>> Fuege neuen Studenten in die Liste ein: Tywin Lannister [   1] ...
    Matrikelnummer    1 eingefügt
>>> Gebe alle erfassten Studenten aus ...
    Matrikelnummer    1: Tywin Lannister
    Matrikelnummer 1289: Viserys Targaryen

=================================================================
==36922==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 64 byte(s) in 1 object(s) allocated from:
    #0 0x7f60a3b16bc8 in malloc (/lib/x86_64-linux-gnu/libasan.so.5+0x10dbc8)
    #1 0x562106b33404 in enqueue (/home/raufu/Schreibtisch/OUTFILE+0x5404)
    #2 0x562106b34d12 in test_enqueue (/home/raufu/Schreibtisch/OUTFILE+0x6d12)
    #3 0x562106b350fd in main (/home/raufu/Schreibtisch/OUTFILE+0x70fd)
    #4 0x7f60a2ed10b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)

Direct leak of 64 byte(s) in 1 object(s) allocated from:
    #0 0x7f60a3b16bc8 in malloc (/lib/x86_64-linux-gnu/libasan.so.5+0x10dbc8)
    #1 0x562106b33404 in enqueue (/home/raufu/Schreibtisch/OUTFILE+0x5404)
    #2 0x562106b34d12 in test_enqueue (/home/raufu/Schreibtisch/OUTFILE+0x6d12)
    #3 0x562106b3514e in main (/home/raufu/Schreibtisch/OUTFILE+0x714e)
    #4 0x7f60a2ed10b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)

Direct leak of 64 byte(s) in 1 object(s) allocated from:
    #0 0x7f60a3b16bc8 in malloc (/lib/x86_64-linux-gnu/libasan.so.5+0x10dbc8)
    #1 0x562106b33404 in enqueue (/home/raufu/Schreibtisch/OUTFILE+0x5404)
    #2 0x562106b34d12 in test_enqueue (/home/raufu/Schreibtisch/OUTFILE+0x6d12)
    #3 0x562106b3521e in main (/home/raufu/Schreibtisch/OUTFILE+0x721e)
    #4 0x7f60a2ed10b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)

Direct leak of 64 byte(s) in 1 object(s) allocated from:
    #0 0x7f60a3b16bc8 in malloc (/lib/x86_64-linux-gnu/libasan.so.5+0x10dbc8)
    #1 0x562106b33404 in enqueue (/home/raufu/Schreibtisch/OUTFILE+0x5404)
    #2 0x562106b34d12 in test_enqueue (/home/raufu/Schreibtisch/OUTFILE+0x6d12)
    #3 0x562106b350ac in main (/home/raufu/Schreibtisch/OUTFILE+0x70ac)
    #4 0x7f60a2ed10b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)

SUMMARY: AddressSanitizer: 256 byte(s) leaked in 4 allocation(s).

Source code:源代码:

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



typedef struct stud_type {
    int matnum;
    char vorname[20];
    char nachname[20];
    struct stud_type* next;
    struct stud_type* tail;
} stud_type;


/* Ist die Datenbank leer?      */
bool is_empty(stud_type const* liste) {
    return !liste;
}


/* Einfuegen eines Elementes
 *
 * Bekommt einen Zeiger auf einen Zeiger der auf das 1. Element der Liste zeigt
 * Bekommt MatNr, Vorname und Nachname des Studenten der eingefügt werden soll
 *
 * Gibt true für Erfolg zurück
 * Gibt false für einen Fehler zurück
 */
bool enqueue(stud_type** studenten_liste, int matnum, char const vorname[20], char const nachname[20]) {
    /* Hole dynamischen Speicher für den neuen Listen Eintrag */

    stud_type* s = (stud_type*)malloc(sizeof(stud_type));
    if (s) {
    /* Befülle den Speicher (vorsicht vor buffer overflows!) */
    s->matnum = matnum;
    strcpy(s->nachname, nachname);
    strcpy(s->vorname, vorname);


    /* Füge den neuen Eintrag in die Liste ein */
        /* Ist die Liste leer ? */
    if (is_empty(*studenten_liste)) {
        *studenten_liste = s;
        s->tail = NULL;
        s->next = s->tail;
        return true;
    }

    /* Sortier den Studenten aufsteigend nach Matrikelnummer ein (matrikelnummern sind einzigartig) */
    stud_type* current = *studenten_liste;
    stud_type* temp = *studenten_liste;
    
    while (true)
    {
        


        if (current->matnum == matnum) {
            return false;
        }
        if (current == *studenten_liste && matnum < current->matnum)
        {
            
            s->next = current;
            s->tail = current->tail;
            *studenten_liste = s;
            return true;
        }
        if (current->matnum > matnum)
        {
            temp->next = s;
            s->next = current;
            s->tail = current->tail;
            return true;
        }
        if (current->matnum < matnum)
        {
            temp = current;
            current = current->next;

        }
        if (current == temp->tail) {
            current = s;
            s->next = NULL;
            s->tail = s->next;
            stud_type* a = *studenten_liste;
            while (a != s->next) {
                a->tail = s->tail;
                a = a->next;
            }
            return true;
        }

    }
    }
    else printf("Malloc failed to allocate memory");
    return false;

}

/* Löschen eines Elementes.
 *
 * Bekommt einen Zeiger auf einen Zeiger der auf das 1. Element der Liste zeigt
 * Bekommt die MatNr des Studenten der zu löschen ist
 *
 * Gibt true für Erfolg zurück
 * Gibt false für einen Fehler zurück
 */
bool dequeue(stud_type** studenten_liste, int matnum) {
    /* Prüfe Randbedingungen */
    if (is_empty(*studenten_liste)) {
    return false;
    }
    /* Finde den Studenten */
  /* Lösche den Studenten und gibt den Speicher frei */

    /* Was muss passieren wenn das 1. Element gelöscht wird? */
    /* Was ist wenn es nicht in der Liste ist? */
    /* ... */
    stud_type* curr = *studenten_liste;
    stud_type* temp = *studenten_liste;
    while (curr->next != curr->tail && curr->matnum < matnum) {
    temp = curr;
    curr = curr->next;
    }

    if (curr->matnum != matnum) {
    /* Rückgabewert: Fehler */
    return false;
    }
    else {
        if (curr == *studenten_liste && &(curr->next) == &(curr->tail)){
            free(curr);
            return true;
        }
        if (&(curr->next) == &(curr->tail))
        {
            stud_type* a = NULL;
            a->tail=a;
            stud_type* s = *studenten_liste;
            while(s != curr)
            {
                s->tail = a;
                s = s->next;
            }
            s->next = a;
            free(curr);
        }
    if (curr == *studenten_liste) {
        temp = curr->next;
        free(curr);
        *studenten_liste = temp;
    }
    else {
        temp->next = curr->next;
        free(curr);
    }
    return true;
    }

}
/* Auslesen eines Elementes
 *
 * Bekommt pointer auf den Listenstart
 * Bekommt MatNr des Studenten der ausgelesen werden soll
 *
 * Schreibt Vorname und Nachname in vorname und nachname
 */
bool get_student(stud_type const* studenten_liste, int matnum, char vorname[20], char nachname[20]) {
    /* Durchsuchen der DB */
    stud_type const* curr = studenten_liste;
    while (curr && curr->matnum < matnum) {
    curr = curr->next;
    }

    if (!curr || curr->matnum != matnum) {
    /* Rückgabewert: Fehler */
    return false;
    }
    else {
    strncpy(vorname, curr->vorname, 19);
    vorname[19] = '\0';
    strncpy(nachname, curr->nachname, 19);
    nachname[19] = '\0';
    /* Rückgabewert: OK */
    return true;
    }
}

static void test_empty(stud_type const* liste) {
    printf(">>> Test ob die Studentenliste leer ist ...\n");

    if (is_empty(liste)) {
    printf("    Die Studentenliste ist leer \n");
    }
    else {
    printf("    Die Studentenliste ist nicht leer \n");
    }
}

static void test_get(stud_type const* liste, int matnum) {
    printf(">>> Test, ob die Matrikelnummer %4i bereits erfasst wurde ...\n", matnum);

    char vorname[20];
    char nachname[20];
    if (get_student(liste, matnum, vorname, nachname)) {
    printf("    Matrikelnummer %4i: %s %s\n", matnum, vorname, nachname);
    }
    else {
    printf("    Matrikelnummer %4i ist unbekannt\n", matnum);
    }
}

static void test_enqueue(stud_type** liste, int matnum, char const* vorname, char const* nachname) {
    printf(">>> Fuege neuen Studenten in die Liste ein: %s %s [%4i] ...\n", vorname, nachname, matnum);
    if (enqueue(liste, matnum, vorname, nachname)) {
    printf("    Matrikelnummer %4i eingefügt\n", matnum);
    }
    else {
    printf("    Matrikelnummer %4i konnte nicht eingefügt werden\n", matnum);
    }
}

static void test_dequeue(stud_type** liste, int matnum) {
    printf(">>> Loesche die Matrikelnummer %4i ...\n", matnum);

    if (dequeue(liste, matnum)) {
    printf("    Matrikelnummer %4i geloescht\n", matnum);
    }
    else {
    printf("    Matrikelnummer %4i war nicht erfasst\n", matnum);
    }
}

static void test_dump(stud_type const* liste) {
    printf(">>> Gebe alle erfassten Studenten aus ...\n");
    for (stud_type const* curr = liste; curr; curr = curr->next) {
    printf("    Matrikelnummer %4i: %s %s\n", curr->matnum, curr->vorname, curr->nachname);
    }
}

/* Test der Listenfunktionen  */
int main(void) {
    /* Initialisierung der Datenbank */
    stud_type* studenten_liste = NULL;
    test_empty(studenten_liste);
    test_enqueue(&studenten_liste, 1234, "Eddard", "Stark");
    test_get(studenten_liste, 1234);
    test_enqueue(&studenten_liste, 5678, "Jon", "Snow");
    test_get(studenten_liste, 1234);
    test_enqueue(&studenten_liste, 9999, "Tyrion", "Lannister");
    test_get(studenten_liste, 1235);
    test_enqueue(&studenten_liste, 1289, "Daenerys", "Targaryen");
    test_dequeue(&studenten_liste, 1234);
    test_empty(studenten_liste);
    test_get(studenten_liste, 5678);
    test_dequeue(&studenten_liste, 9998);
    test_enqueue(&studenten_liste, 1289, "Viserys", "Targaryen");
    test_dequeue(&studenten_liste, 5678);
    test_enqueue(&studenten_liste, 1, "Tywin", "Lannister");
    test_dump(studenten_liste);

   

    

    return 0;
}

Debug-Attempt:调试尝试:

d3 d4

It appears that enqueue() is creating variable stud_type* s and allocating it memory using malloc() .似乎enqueue()正在创建变量stud_type* s并使用malloc()为其分配 memory 。 However, I can not find a place where it is free() 'd.但是,我找不到它是free()的地方。 It seems like dequeue() should do this, but from what I can tell, it is not called for some of the allocations.似乎dequeue()应该这样做,但据我所知,某些分配不需要它。 I could be wrong though, as I don't have access to a C compiler right now.不过我可能是错的,因为我现在无法访问 C 编译器。

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

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