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

使用malloc()和free链接列表的正确方法,c,pointers,struct,linked-list,free,C,Pointers,Struct,Linked List,Free,对于链表,我试图更好地理解malloc()。这是否为指向列表的指针以及其中的字段创建了内存? 例如: 除此之外,如果我试图释放此节点及其内部的字段。我是否需要遍历所有字段(请参见下面的代码)。这只是释放指针(从上面的行创建)还是释放指针和字段 free(someStructPtr); 举个更直接的例子。我有一个列表结构,我试图为这个结构和它的字段分配空间。我希望确保正确创建、删除和使用stdrup()。我的代码如下: 结构声明: typedef struct ListNode_st {

对于链表,我试图更好地理解malloc()。这是否为指向列表的指针以及其中的字段创建了内存? 例如:

除此之外,如果我试图释放此节点及其内部的字段。我是否需要遍历所有字段(请参见下面的代码)。这只是释放指针(从上面的行创建)还是释放指针和字段

free(someStructPtr);
举个更直接的例子。我有一个列表结构,我试图为这个结构和它的字段分配空间。我希望确保正确创建、删除和使用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);
}

在回答你的问题之前,让我们先热身一下

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


最后同样重要的一点是,还有其他类型的内存我在这里不会提及。

请不要从
malloc()
强制转换返回值

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

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

当您使用
free()
分配的内存时,同样的情况也适用-
free()
对您的结构一无所知,或者即使它是一个结构。在
free()
为结构分配内存之前,由您决定该结构中的任何内存分配。它不会释放结构。它释放结构所在的内存

因此答案是肯定的,您确实需要遍历整个数据结构,否则任何嵌套的内存分配指针都将丢失,从而导致内存泄漏。

这会为指向列表的指针以及其中的字段创建内存吗? 给定您的结构类型

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

请注意,在大多数链表实现中,在创建新节点时,不会为
next
分配内存;该字段用于指向列表中先前分配的另一个节点。在当前节点之后插入节点时,将设置该值

除此之外,如果我试图释放此节点及其内部的字段。我是否需要遍历所有字段(请参见下面的代码)。这只是释放指针(从上面的行创建)还是释放指针和字段

free(someStructPtr);
在删除整个节点之前,需要先释放所有已分配的成员,例如

free( l->str );
free( l );

释放
l
不会释放
l->str
指向的内存

你所做的是正确的(至少没有明显的错误),但你的想法有点偏颇
malloc
仅为您分配一块内存。它不知道也不关心里面的田地。是的,
free
只释放一层,所以如果需要,你需要释放里面的字段。但是有一个经常争论的问题:。我通常不使用C,除非我不确定我在做什么,但现在我肯定不会感谢你!C中的“不要选演员”总是出现。而且总是指向那个惯用问题的链接。我的推论是(和往常一样):不要使用C-iffffff,你肯定在未来500年内代码只能由C-compiler编译。这看起来很棒。根据您的回答,我猜测设置字段(如listPointer->next=NULL)已经足够了,我不需要对其进行malloc。其次,我需要确保销毁列表中的str字段。我一直在问,你的free()语句是否会破坏list->str以及list指针。你能解释一下为什么我们
malloc()
free()
用于
str
字段,而不是
next
字段吗?我将最终为这个节点指定一个地址(在大多数情况下)。所以我相信我需要
malloc()。我想这可能是我对C中的链表产生误解的根源。再次感谢@纳普金斯恐怖,但不是下一个领域<代码>下一步
委托给
列表\u销毁(列表->下一步)。谢谢!我只希望你能像我这样做,但我明白了。我对栈、堆和低级计算机硬件有很好的理解,但我只是想知道为什么或者为什么不在节点被malloc’ed后malloc节点内部的字段(特别是对于
next
字段,因为它需要我malloc另一个结构)。这一切都取决于您计划做什么。在he上单独分配每个节点
l->str = malloc( N * sizeof *l->str ); // allocate N characters
l->str = strdup( str );
free( l->str );
free( l );