[英]How to free more complex nested structs
評論中的解決方案。
typedef struct Vertex {
int i;
int color;
} vertex;
typedef struct Edge {
vertex v1;
vertex v2;
} edge;
typedef struct Node {
void *p;
struct Node *next;
} node;
基本上,這是一個(節點的)鏈表。 在我的程序中,我知道節點數組是否包含邊或頂點。
我不確定如何正確釋放邊緣列表,我嘗試了以下方法:
static void freeEdgeList(node *list) {
if (list == NULL) return;
node *ptr = list;
node *tmp;
do {
tmp = ptr->next;
free(&((*((edge *)(ptr->p))).v1));
free(&((*((edge *)(ptr->p))).v2));
free(ptr->p);
free(ptr);
} while ((ptr = tmp) != NULL);
}
因為我的結構Edge不存儲指針,是否足以釋放邊緣結構而不釋放存儲在邊緣中的頂點? 我有點困惑。
編輯:
static int addEdge(edge *e, node **list) {
if ((*list) == NULL) {
(*list) = malloc(sizeof(node));
if ((*list) == NULL) return -1;
(*list)->p = malloc(sizeof(edge));
if ((*list)->p == NULL) return -1;
memcpy(&((*list)->p), &e, sizeof(edge));
(*list)->next = NULL;
} else {
node *tmp = (*list);
while (tmp->next != NULL) {
tmp = tmp->next;
}
tmp->next = malloc(sizeof(node));
if (tmp->next == NULL) return -1;
tmp = tmp->next;
tmp->p = malloc(sizeof(edge));
if (tmp->p == NULL) return -1;
tmp->next = NULL;
memcpy(&(tmp->p), &e, sizeof(edge));
}
return 0;
}
這是將邊緣添加到列表的功能(最初傳入的列表為NULL)。 似乎正確添加了邊緣,因為我可以將列表輸出到控制台了。 但是,如果我嘗試釋放:
static void freeEdgeList(node *list) {
while (list) {
node *tmp = list;
list = list->next;
free(tmp->p);
free(tmp);
}
}
我得到不同的錯誤(segfault,無效的指針)
您只能准確地free
malloc
和family返回的內容。 由於您大概調用了malloc
來分配node
,因此只需要釋放一個node
。
vertex
和edge
都不包含作為指針的字段,因此沒有其他可釋放的空間。 您需要做的只是:
static void freeEdgeList(node *list) {
while (list) {
node *tmp = list;
list = list->next;
free(tmp->p);
free(tmp);
}
}
編輯:
在添加邊的代碼中,您錯誤地這樣做:
memcpy(&((*list)->p), &e, sizeof(edge));
...
memcpy(&(tmp->p), &e, sizeof(edge));
由於e
是edge *
,所以這樣做是將指針值 e
復制到字段p
而不是它指向的字段。 這導致由p
指向的edge
對象具有無效值。 相反,您想要:
memcpy((*list)->p, e, sizeof(edge));
...
memcpy(tmp->p, e, sizeof(edge));
這將復制e
指向的edge
中包含的值。
規則是,如果不分配它,則不會釋放它。 如您所說,結構Edge
不包含任何動態內存分配或指針,因此您不會自己釋放它們。 內存被分配為Edge
一部分,並在釋放時釋放。
因此,從v1
和v2
刪除free()
,僅使用free(ptr->p)
。
是的,這是正確的。 由於您不是在malloc()
繪制 vertex
(它們不是指針,而是在Edge結構內部分配的變量free()
,因此,針對Edge結構的簡單free()
就足夠了
編輯:似乎我還不太明白。
感謝您的幫助,非常感謝! 這對我來說很清楚。
while (list) {
node *tmp = list;
list = list->next;
free(&(tmp->p));
free(tmp);
}
這種解決方案有效,我需要將指針的地址傳遞給free,而不是指針本身,盡管我不太清楚為什么。
正如其他人提到的, freeEdgeList
需要修復[因此請遵循他們的回答]。
在addEdge
,您的memcpy
調用不正確。 您正在向/從指針的地址復制,而不是指針指向的地址 。
您需要: memcpy((*list)->p, e, sizeof(edge))
和memcpy(tmp->p, e, sizeof(edge))
另外,在addEdge
,如果*list == NULL
,則不要將其設置為first / new元素。
而且,代碼可以簡化一些。 例如,在任何地方使用*list
都比較麻煩。
這是修復了memcpy
和*list
錯誤的重構版本:
static int
addEdge(edge *e, node **list)
{
node *head = *list;
node *cur;
node *prev;
int ret = -1;
// find the end of the list
prev = NULL;
for (cur = head; cur != NULL; cur = cur->next)
prev = cur;
do {
// allocate new node
cur = malloc(sizeof(node));
if (cur == NULL)
break;
cur->next = NULL;
// add pointer to new edge
cur->p = malloc(sizeof(edge));
if (cur->p == NULL) {
free(cur);
break;
}
// copy in the edge data
memcpy(cur->p,e,sizeof(edge);
// link in new node
if (prev != NULL)
prev->next = cur;
else
head = cur;
// adjust list pointer
*list = head;
ret = 0;
} while (0);
return ret;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.