正确使用malloc()和免费链接列表的方法

时间:2015-04-08 18:12:58

标签: c pointers struct linked-list free

我想在链表上更好地理解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);
}

4 个答案:

答案 0 :(得分:3)

请不要从malloc()投射返回值。

malloc(sizeof(SomeStruct))

为一个结构分配足够的内存,然后必须初始化结构中的每个字段。

calloc(1, sizeof(SomeStruct))

执行相同的操作,但结构的每个字节都初始化为0malloc()calloc()对您的结构一无所知,只是分配您要求的内存量。它们返回一个void*指针,以便它们可以用于任何他们既不知道也不关心的数据类型。

当你来到free()分配的内存时,同样适用 - free()对你的结构一无所知,或者即使它一个结构。在free()结构的内存之前,由free()在该结构中的任何内存分配决定你。它没有释放结构。它释放了结构所在的内存。

所以答案是肯定的,你需要遍历整个数据结构,否则任何嵌套的内存分配指针都将丢失,导致内存泄漏。

答案 1 :(得分:2)

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);
}

答案 2 :(得分:2)

在我们解决你的问题之前,先让我们热身。

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()是用于在堆上分配内存的函数。

最后,至少还有其他类型的内存我不会在这里提及。

答案 3 :(得分:1)

这是否为指向列表的指针以及其中的字段创建内存?

给出你的结构类型

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指向的内存。