使用链接列表时在C中释放动态分配的内存

时间:2017-03-19 19:33:51

标签: c memory-management struct

我试图通过试验各种案例来熟悉C中的链接列表,我有一个问题。我编写了这段代码,我不确定哪种方法可以释放动态分配的内存。只是免费(S);或者我必须免费写(Top);如果是的话,这两个命令的顺序是否重要?另外,除此之外,这段代码是否正确编写?如果你不介意的话,我想要一个彻底的解释,我没有编码任何东西5年。

#include <stdlib.h>
#include <stdio.h>

typedef char StackType;

typedef struct StackNodeTag
   {StackType T;
    struct StackNodeTag *Link;
   } StackNode;

typedef struct StackTag
   {struct StackNodeTag *Top;
   } Stack;

typedef Stack *StackPointer;

int main (void)
   {StackPointer S;

    S = malloc (sizeof (Stack));
    S->Top = malloc (sizeof (StackNode));

    S->Top->T = 'c';
    S->Top->Link = NULL;

    free (S->Top);
    free (S);

    return 0;
   }

4 个答案:

答案 0 :(得分:1)

是的,您必须释放使用malloc或类似功能分配的所有内容,订单确实很重要。

由于您在另一个项目中有动态分配的项目,因此您必须从内到外解放。如果您在S之前释放S->Top,则可能会导致内存泄漏,因为您在处理内容时释放了包含malloc数据的内存。

答案 1 :(得分:1)

malloc的通话次数应与free的通话次数相同。

你所拥有的将会正常运作。就订单而言,您只需要确保可以访问要释放的内存。例如,如果您先执行free(S),则在代码中,由于free(S->Top)不再指向有效内存,因此您无法成功调用S

答案 2 :(得分:0)

此代码是正确的。每个malloc()调用都应该有一个相应的free()调用,所以你在这里需要两个免费调用--S和Top。

在大多数情况下,您对free()的调用顺序无关紧要。每个malloc()调用都返回一个指针。只要使用malloc返回的相同指针调用free,就可以按任意顺序释放数据。

但是,在这种情况下,free()调用的顺序很重要,因为您对Top的唯一引用是通过S.一旦释放S,就不应该引用存储在S引用的结构中的任何数据。

在许多实现中,如果在释放后直接访问释放结构中的数据,您将会很幸运,数据仍然存在。但是,这是不好的做法,因为无法保证数据保持原样。因此,您的免费电话(S-> Top)必须在免费(S)之前。

例如,释放这些数据的同样有效的方法是1)将StackNode指针保存到临时变量,2)free S,以及3)使用临时变量释放Top。但是,你写这个的方式更好,因为它更简单。

答案 3 :(得分:0)

您对malloc和free的使用是正确的,并且是唯一有效的订单。

S指向的堆栈必须存在才能访问/分配其元素Top。此外,如果S在S-> Top之前被释放,你将孤立S-> Top所指向的内存,无法访问或释放它(如果Stack指向的话,你不能释放S-&gt; Top; S不再存在。)

我还建议纠正一些风格问题,以使您的代码更清晰。

// Original
int main (void)
{StackPointer S;
  ..
}

使用与开括号位于同一行的代码很难阅读。并不是说它无法被理解,只是它一眼就看不出来。

// Easier to read
int main(void)
{
  StackPointer S;
  ..
}

/* Alternate Style, many will say to use
   the above for functions and this for all
   other bracket notation (structs/unions, control flow) */
int main(void) {
  StackPointer S;
  ..
}

这是两种常用的风格。

typedef Stack *StackPointer;
...
StackPointer S;

这是非常不必要的,需要读者查看StackPointer是什么。

Stack *S;

这不需要typedef,很明显S是指向Stack类型的指针。

此外,由于堆栈可能始终存在,您可以静态创建它(如果您愿意)。这也将改变您访问其成员的方式

修改后的代码

#include <stdlib.h>
#include <stdio.h>

typedef char StackType;

typedef struct StackNodeTag {
    StackType T;
    struct StackNodeTag *Link;
} StackNode;

typedef struct {
    StackNode *Top;
} Stack;

int main (void)
{
    Stack S;

    S.Top = (StackNode *) malloc(sizeof(StackNode));

    S.Top->T = 'c';
    S.Top->Link = NULL;

    free (S.Top);

    return 0;
}