簡體   English   中英

正確使用malloc()並與鏈接列表一起使用的正確方法

[英]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指向一個足以容納兩個指針的內存塊; 然而,什么也沒有被分配給任何strnext 指向 您將必須分別為字符串和下一個節點分配內存:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM