[英]Correct way to use malloc() and free with linked lists
當涉及鏈表時,我試圖更好地理解malloc()。 這會為指向列表及其內部字段的指針創建內存嗎? 如:
SomeStruct * someStructPtr = (SomeStruct *) malloc(sizeof(SomeStruct));
除此之外,如果我嘗試釋放該節點及其內部的字段。 我是否需要遍歷所有字段(請參見下面的代碼)。 這只是釋放指針(從上面的行創建)還是釋放指針和和字段。
free(someStructPtr);
舉一個更直接的例子。 我有一個List的結構,我正在嘗試為該結構及其創建時的字段分配空間。 我想確保我正確地創建,刪除和使用stdrup()。 我的代碼如下:
結構聲明:
typedef struct ListNode_st
{
char * str;
struct ListNode_st * next;
} List;
創建節點:
List * List_createNode(const char * str){
List * listPointer = (List *) malloc(sizeof(List));
//make sure there was enough memory
if(listPointer == NULL)
return NULL;
//malloc for next
listPointer.next = (List *) malloc(sizeof(List *));
if(listPointer.next == NULL)
return NULL;
listPointer.next = NULL;
//malloc for str
listPointer.str = strdup(str);
//make sure enough space for the string to be copied
if(listPointer.str == NULL)
return NULL;
//return value
return listPointer;
}
刪除節點:
void List_destory(List * list){
//base case -- (last item)
if(list == NULL)
return;
//recurse case -- (there are more items)
List_destroy(list->next);
if(list->str != NULL)
free(list->str);
if(list->next != NULL)
free(list->next);
free(list);
}
請不要malloc()
的返回值。
malloc(sizeof(SomeStruct))
為一個結構分配足夠的內存,然后必須初始化該結構中的每個字段。
calloc(1, sizeof(SomeStruct))
相同,但是結構的每個字節都初始化為0
。 malloc()
和calloc()
對您的結構一無所知,它們只是分配您要的內存量。 它們返回一個void*
指針,以便可以將它們用於任何既不知道也不關心的數據類型。
當您使用free()
分配的內存時,同樣適用free()
對您的結構一無所知,即使它是一個結構也不知道。 在free()
結構的內存之前,由您決定free()
該結構內的任何內存分配。 它不會釋放結構。 它釋放結構所在的內存。
因此答案是肯定的,您確實需要遍歷整個數據結構,否則任何嵌套的內存分配指針都將丟失,從而導致內存泄漏。
List * List_createNode(const char * str){
List * listPointer = (List *) malloc(sizeof(List));
if(listPointer == NULL)
return NULL;
listPointer->next = NULL;
listPointer->str = strdup(str);
if(listPointer->str == NULL){
free(listPointer);
return NULL;
}
return listPointer;
}
void List_destory(List * list){
if(list == NULL)
return;
List_destroy(list->next);
free(list->str);
free(list);
}
在解決您的問題之前,讓我們熱身一點。
int x = 42;
x的記憶來自哪里? 分配了嗎? 哪里? 如果此行位於函數內部,則答案是:它是“自動”變量,並且它使用的內存在堆棧中。
int * y = NULL;
y的記憶從何而來? 這里沒有調用malloc()
,但是y
存在。
現在,您應該已經可以回答問題的第一部分了。 在這種情況下, malloc()
不會為指針分配內存。
struct Node
{
struct Node * next;
int value;
};
void InitNode( Node *node, int value )
{
if(NULL != node)
{
node->next = NULL;
node->value = value;
}
}
// Not on HEAP, not on stack! Where?
// This one gets its memory from "initvars" section.
int foo = 69;
int main( int argc, const char * argv[] )
{
struct Node n1; // instance located on stack...
InitNode(&n1); // no malloc() to be seen...
// Instance located on HEAP, but n2, the pointer is located on stack,
// just like an int x = 42 would be.
struct Node *n2 = malloc(sizeof(struct Node));
}
因此,顯然,為了弄清malloc()
作用,需要了解不同類型的內存以及如何處理它。
到目前為止,我們看到了“自動”(又名“堆棧存儲器”),我們看到了“ initvars”存儲器。 我們看到了“堆”內存。 malloc()是用於在堆上分配內存的函數。
最后同樣重要的是,還有其他類型的內存,我在這里不會提及。
這會為指向列表及其內部字段的指針創建內存嗎?
給定你的結構類型
typedef struct ListNode_st
{
char * str;
struct ListNode_st * next;
} List;
以下調用將為該結構的實例創建內存:
List *l = malloc( sizeof *l ); // note no cast, operand of sizeof
l
指向一個足以容納兩個指針的內存塊; 然而,什么也沒有被分配給任何str
或next
指向 。 您將必須分別為字符串和下一個節點分配內存:
l->str = malloc( N * sizeof *l->str ); // allocate N characters
要么
l->str = strdup( str );
請注意,在大多數鏈表實現中,創建新節點時不會為next
分配內存。 該字段旨在指向列表中另一個先前分配的節點。 在當前節點之后插入一個節點時,將對其進行設置。
除此之外,如果我嘗試釋放該節點及其內部的字段。 我是否需要遍歷所有字段(請參見下面的代碼)。 這只是釋放指針(從上面的行創建)還是釋放指針和和字段。
您需要先釋放所有分配的成員,然后再刪除整個節點,例如
free( l->str );
free( l );
釋放l
不會釋放l->str
指向的內存。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.