繁体   English   中英

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

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

我使用以下命令编译了代码:

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

源代码中唯一重要的功能是在memory应该被释放的地方出队和在memory被分配的地方入队。

我使用调试器查看错误在哪里(见下图),我认为 function “dequeue”不会从堆中释放 memory,该堆用于我的列表条目。 但我不知道为什么 memory 没有再次释放。 变量 curr 是指向必须删除的条目的指针,在调用空闲 function 后,memory 地址在运行时不会改变。

在 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).

源代码:

#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;
}

调试尝试:

d3 d4

似乎enqueue()正在创建变量stud_type* s并使用malloc()为其分配 memory 。 但是,我找不到它是free()的地方。 似乎dequeue()应该这样做,但据我所知,某些分配不需要它。 不过我可能是错的,因为我现在无法访问 C 编译器。

暂无
暂无

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

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