[英]doubly linked list freeing memory valgrind error
嗨,我正在嘗試釋放分配給雙鏈表的內存,但是當我用valgrind檢查它時,free_all函數出現了一些錯誤(我認為),但是我不知道如何避免它。
我認為在free_all函數中,我使用了temp和node指針錯誤,或者我需要先分配它,然后再使用它們,但是當我嘗試這種方法時,valgrind仍然給了我一些錯誤。
#include <stdio.h>
#include <stdlib.h>
/*
to compile it:
gcc -g -Wall -ggdb3 double_linkedlist2.c -o double_linkedlist
to check for memory leak and error:
valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose --log-file=valgrind-out.txt ./double_linkedlist
*/
typedef struct listitem
{
struct listitem *next; // pointer to next item
struct listitem *prev; // pointer to previous item
int data; // some data
} ITEM;
int main (void)
{
// prototype functions
void free_all (ITEM *lst_ptr);
// Variables
ITEM *p_temp, *head;
head = malloc (sizeof (ITEM)); // head will keep first and last element in its pointers
head -> next = head; // the last element in the list (at first head -> next and head -> prev will point to the head)
head -> prev = head; // the first element in the list
for (int i = 0; i < 3; i++)
{
p_temp = malloc (sizeof (ITEM)); // allocate some memory for the new list item
p_temp -> data = i; // set the list item's data to the loop count so that we can see where it is in the list
p_temp -> next = head -> next; // this will insert at the FRONT of the list
head -> next = p_temp; // and set the list head to the newly created list item
p_temp -> prev = head; // this will insert at the BACK of the list
p_temp -> next -> prev = p_temp; // and set the list 'tail' to the newly created item
}
// now let's see what we got going forward
printf ("Going forward\n");
p_temp = head -> next;
while (p_temp != head)
{
printf ("forward list item: current is %p; next is %p; prev is %p; data is %d\n", p_temp, p_temp -> next, p_temp -> prev, p_temp -> data);
p_temp = p_temp -> next;
}
// now let's see what we got going backward
printf ("Going backwards\n");
p_temp = head -> prev;
while (p_temp != head)
{
printf ("backward list item; current is %p; next is %p; prev is %p; data is %d\n", p_temp, p_temp -> next, p_temp -> prev, p_temp -> data);
p_temp = p_temp -> prev;
}
printf ("\n");
free_all (head);
return 0;
}
void free_all (ITEM *head)
{
ITEM *temp, *node;
node = head;
while (node != head -> prev)
{
temp = node;
printf ("freed list item: current is %p; next is %p; prev is %p; data is %d\n", temp, temp -> next, temp -> prev, temp -> data);
node = node -> next;
free (temp);
}
free (node);
free (head);
}
您的free_all至少有兩個錯誤:while條件引用head-> prev,但是在第一次迭代中您釋放了head(在free之后使用)。 退出循環后,盡管在第一次迭代中釋放了頭部,您仍然可以釋放頭部。 free_all()適用於單個元素的情況。
修改后,valgrind中沒有錯誤或內存泄漏
void free_all (ITEM *head)
{
ITEM *temp, *node = NULL;
node = head -> next;
while (node != head -> prev)
{
temp = node;
printf ("freed list item: current is %p; next is %p; prev is %p; data is %d\n", node, node -> next, node -> prev, node -> data);
node = node -> next;
free (temp);
}
node = head -> prev;
printf ("freed list item: current is %p; next is %p; prev is %p; data is %d\n", node, node -> next, node -> prev, node -> data);
free (head);
free (node);
}
這篇文章是由mevets撰寫的,是對我的解決方案的編輯,但我認為最好也將其包含在線程中:
mevets:
我傾向於這樣的事情:
void Unlink(ITEM **head, ITEM *t) {
if (t->next == t) {
/* remove head */
*head = NULL;
} else {
t->prev->next = t->next;
t->next->prev = t->prev;
if (t == *head) {
*head = t->next;
}
}
}
/*
remove and return the element after head
*/
ITEM *Pop(ITEM **head) {
ITEM *node;
if ((node = *head) != NULL) {
node = node->next;
Unlink(head, node);
}
return node;
}
void free_all (ITEM *head) {
ITEM *node;
while ((node = Pop(&head)) != NULL) {
free(node);
}
}
這將列表維護(取消鏈接)與訂購(Pop)和內存管理(free_all)分開。 這給您留下了更多的邊界,您可以在其中對列表進行斷言,例如在取消鏈接之前和之后,列表應該是有效的並且可以檢查。 此外,如果可以同時訪問列表,則可以將Pop()放在方括號內,以最大程度地減少沖突。
緩存分配器本身就是一件事,但是合同的一個典型部分是您釋放處於已知狀態的節點,這樣當重新分配節點時,它可以跳過它們的構造。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.