[英]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;
}
调试尝试:
似乎enqueue()
正在创建变量stud_type* s
并使用malloc()
为其分配 memory 。 但是,我找不到它是free()
的地方。 似乎dequeue()
应该这样做,但据我所知,某些分配不需要它。 不过我可能是错的,因为我现在无法访问 C 编译器。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.