free()后将指针设置为NULL总是一个好的做法吗?

8

可能是重复问题:
释放内存后将变量设置为NULL

我正在学习良好的C编程实践,我的朋友告诉我,在free()(或调用特定的释放函数)之后总是要将指针设置为NULL。

例如:

char* ptr = malloc(100);
...
free(ptr);
ptr = NULL;

或者

struct graph* graph = create_graph();
...
destroy_graph(graph);
graph = NULL;

为什么这是一个好的实践?

更新:阅读答案后,我认为这是一个非常糟糕的实践!我隐藏了可能的double-free()错误。这怎么可能是一个好的实践?我感到震惊。

谢谢,Boda Cydo。


@bodacydo请看页面右侧的“相关问题”。 - anon
1
怎么做呢?释放指针并将其设置为NULL可以释放内存。如果您决定释放NULL,则应该得到一个assert或其他警告。双重释放内存比释放NULL要难得多。 - Michael Dorgan
3
如果你释放 NULL,它会默默地什么都不做,没有断言。这是个好事情,因为它使得清理代码更容易,需要更少的 if;但我至少可以理解OP所说的“隐藏了BUG”的观点。 - zwol
2
@bodacydo:它可以隐藏双重释放,但不这样做可能会隐藏野指针错误(在内存被释放后访问指针)。这是一种权衡,所以它并不一定是坏的(但也不一定是好的)。个人认为对空指针进行额外释放不一定是一个 bug,但访问野指针总是错误的,所以我支持将其赋值为“NULL”。 - jamesdlin
1
我认为这个逻辑是,双重释放内存的错误比使用已经释放的内存更小。假设你在一个触发NULL解引用信号的机器上,你很快就会发现一个关键性的错误。 - Darron
显示剩余3条评论
4个回答

14

虽然这样做不会有害,但也并非总是有益的。需要考虑的问题是,指针很容易存在多个副本,而你只有可能将其中一个设置为 NULL。其中经典的例子是:

void free_graph(graph *g)
{
    ...
    free(g);
    g = NULL;  // not useful in this context
}

问题在于你只将局部指针free_graph设置为NULL,而调用free_graph的调用者仍然拥有原始值。


6

有些人认为这是一种好的做法,因为它可以防止您在释放内存后意外访问该内存。


1
阅读了答案后,我发现这是一种不好的做法 - 我隐藏了双重释放的错误!这怎么可能是一种好的做法呢? - bodacydo
1
实际上,它并不会自动阻止您访问它,但您始终可以(而且应该)检查空指针,但您无法确定非空指针是否有效。因此,这是一个好的实践。 - cypheon
我还没有被说服这是一个好的习惯。 - bodacydo

2

我不赞成这种做法。如果你真的需要指定一个值,请将其设置为(void*)0xdeadbeef。首先检查你的CRT能做什么。一个好的调试分配器会将释放的内存设置为可能在指针被释放后使用时导致崩溃的模式。虽然这并不保证一定会发生。但不改变指针值则是更好(也更快)的解决方案。


-5

我认为是的...

当你使用完一部分内存后,我们应该使用free()函数释放它。这样可以使得被释放的内存可以用于其他用途,例如进一步的malloc()调用。

free()函数需要一个指向内存的指针作为参数,并释放该指针所指向的内存...

希望这能帮到你... :)


6
这不是对问题的回答。bodacydo并没有问是否应该释放内存。他在问,释放内存后是否应该将指针设置为NULL。 - Platinum Azure

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接