当ptr为NULL时,使用free(ptr)会破坏内存吗?

149

从理论上讲,我可以说

free(ptr);
free(ptr); 

由于我们正在释放已经被释放的内存,这是一种内存损坏。

但如果

free(ptr);
ptr=NULL;
free(ptr); 

由于操作系统会以未定义的方式表现,因此我无法进行实际的理论分析来确定正在发生什么。 无论我做什么,这是内存损坏还是不是?

释放空指针是否有效?


1
不确定C的自由标准,但在C++中delete(NULL)是完全有效的,所以我想free(NULL)也应该是有效的。 - Priyank Bolia
16
@Pryank:在C++中,“delete NULL”是无效的。Delete只能应用于具体类型的空指针值,而不能应用于“NULL”。 “delete (int*) NULL”是合法的,但“delete NULL”不是。 - AnT stands with Russia
这意味着如果一个指针指向NULL,free函数不会执行任何操作。这是否意味着!!!!在我们的编码中每次想要释放内存时,可以简单地用ptr=NULL替换free(ptr)? - Vijay
4
不。如果ptr指向内存,并且您没有调用free释放它,那么内存将泄漏。将其设置为NULL只是失去了对该内存的控制,并导致内存泄漏。如果ptr恰好是NULL,则调用free不会有任何操作。 - GManNickG
2
@benjamin:嗯?是什么让你得出可以用“ptr = NULL”替换“free(ptr)”的结论?没有人说过这样的话。 - AnT stands with Russia
显示剩余3条评论
11个回答

263

7.20.3.2函数free

概要

#include <stdlib.h> 
void free(void *ptr); 

描述

free函数导致指向ptr的空间被释放,即可用于进一步分配。如果ptr是一个空指针,则不会发生任何操作。

请参见ISO-IEC 9899

话虽如此,在查看不同的代码库时,你会注意到人们有时会这样做:

if (ptr)
  free(ptr);

这是因为一些 C 运行时库(至少在 PalmOS 上是如此)在释放 NULL 指针时会崩溃。

但是现在,我相信按照标准的要求,可以安全地假定 free(NULL) 是一个空操作。


37
不,ptr=NULL并不能代替free(ptr),两者完全不同。 - Prasoon Saurav
14
不,这意味着在ptr为空时调用free(ptr)没有任何副作用。但是,在任何情况下,使用malloc()calloc()分配的每个内存块都必须使用free()释放。 - Gregory Pakosz
7
ptr=NULL 确保即使您意外调用了 free(ptr),您的程序也不会导致段错误。 - Prasoon Saurav
2
请注意,尽管C标准表示它是一个无操作(no-op),但并不意味着每个C库都会像那样处理它。我曾经看到过free(NULL)导致崩溃的情况,因此最好避免首先调用free。 - Derick
9
@WereWolfBoy 的意思是在调用 free() 之前通过将指针与 NULL 进行比较来避免使用 free(NULL) - Gregory Pakosz
显示剩余4条评论

31

所有符合标准的 C 库版本都将 free(NULL) 视为无操作。

尽管如此,曾经有一些版本的 free 在 free(NULL) 时会崩溃,这就是为什么你可能会看到一些防御性编程技巧建议:

if (ptr != NULL)
    free(ptr);

10
“-1 [citation needed]。因为一些过时或者无根据的说法而改变代码风格是一个不好的主意。” - Tomas
48
@Tomas - 我从未建议改变风格,我只是解释为什么在某些风格中你仍然可能看到这个建议。 - R Samuel Klatchko
5
@Tomas 3BSD(http://www.winehq.org/pipermail/wine-patches/2006-October/031544.html)和PalmOS各一台(二手)。 - Douglas Leeder
8
@Tomas: 问题出现在像 Version 7 Unix 这样的系统中。当我学习时,free(xyz) 其中 xyz == NULL 在我所学的机器上(ICL Perq 运行 PNX,它基于带有一些 System III 扩展的 Version 7 Unix)是一种导致瞬间灾难的方法。但是我已经很长时间没有用这种方式编写代码了。 - Jonathan Leffler
2
Netware在释放NULL时崩溃了...(我刚刚调试了它的崩溃...) - Calmarius
显示剩余4条评论

14
如果ptr为NULL,则不执行任何操作。这是文档中的说明。

你的意思是自由不会执行任何操作吗? - Vijay
2
本杰明,这正是它的意思。如果它知道参数的空值,你会期望它执行什么? - Michael Krelin - hacker

13

我记得在PalmOS上工作时,free(NULL)会导致崩溃。


4
有趣——这使得它成为继3BSD之后第二个崩溃的平台。 - Douglas Leeder
2
如果我没记错的话,在Palm上没有C标准库。相反,有一个大多数不受支持的头文件,将标准库调用映射到Palm OS SDK。很多东西表现得出乎意料。在Palm工具箱中,与标准库相比,崩溃NULL是其中一个最大的运行差异之一。 - Steven Fisher
PalmOS是一个独立的C实现,因此没有义务提供标准C库。它的free对应函数(MemPtrFree)不符合标准,而free被别名为MemPtrFree,以提供类似标准的API(粗略尝试)。 - jamesdlin

9
free(ptr);
ptr=NULL;
free(ptr);/*This is perfectly safe */

您可以放心地删除一个NULL指针。在这种情况下不会执行任何操作。换句话说,free()在NULL指针上不执行任何操作。


8

推荐用法:

free(ptr);
ptr = NULL;

请参见:

man free

     The free() function deallocates the memory allocation pointed to by ptr.
     If ptr is a NULL pointer, no operation is performed.

在使用free()释放内存后,将指针设置为NULL,再次调用free()时不会执行任何操作。


3
这也有助于用调试器检测段错误。很明显,当p=0时,在p->do()处出现的段错误是由于使用了已释放的指针。但在调试器中看到p=0xbfade12时就不那么明显了 :) - neuro

7

free(NULL) 在C语言中是合法的,同样 delete (void *)0delete[] (void *)0 在C++语言中也是合法的。

顺便提一下,多次释放内存通常会引起某种类型的运行时错误,但不会破坏任何东西。


2
在C++中,delete 0是不合法的。delete关键字明确要求一个指针类型的表达式。将delete应用于一个具有类型的空指针值是合法的,但不能应用于0(也不能应用于NULL)。 - AnT stands with Russia
1
你也不能删除 void* :P 它应该运行哪些析构函数? - GManNickG
1
@GMan:只要它是空指针,你就可以删除void * - AnT stands with Russia
好的,说得对。我忘记了我们只处理特定的空值。 - GManNickG
通常不会破坏任何东西,但不能保证。ASLR使这种情况变得不太可能,但仍然不是不可能的:buf1=malloc(X); free(buf1);buf2=malloc(X);free(buf1); - 如果你运气不好,buf2的地址与buf1完全相同,你就会意外地两次释放buf1,在第二次释放buf1时,你实际上悄悄地释放了buf2,而没有引起任何(立即)错误/崩溃/等等。(但下次尝试使用buf2时,你仍然可能会遇到崩溃 - 如果你正在运行ASLR,则这种情况非常不可能发生)。 - hanshenrik

4
如果ptrNULL,那么在C语言中使用free(ptr)是安全的。然而,大多数人不知道的是,NULL不一定等于0。我有一个很好的老派例子:在C64上,地址0处是一个IO端口。如果你在C语言中编写一个访问该端口的程序,你需要一个值为0的指针。相应的C库必须区分0和NULL。祝好!

有趣的事实,让我感到惊讶。让我觉得有必要围绕空指针问题/答案进行一次旅行。 - arthropod
然而,您将永远无法释放此端口。 - Polluks

1

不是内存损坏,而是行为取决于实现方式。 按照标准,它应该是合法的代码。


0

虽然现在很安全,但我总是使用以下宏来释放指针:

#define FREE(ptr)      \ 
{                      \
    if ((ptr) != NULL) \
    {                  \
        free(ptr);     \
        (ptr) = NULL;  \
    }                  \
}

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