释放后将变量设置为NULL


156

在我公司中,有一条编码规则说,释放所有内存后,将变量重置为NULL。例如 ...

void some_func () 
{
    int *nPtr;

    nPtr = malloc (100);

    free (nPtr);
    nPtr = NULL;

    return;
}

我觉得,在如上所示代码的情况下,设置为NULL没有任何意义。还是我错过了什么?

如果在这种情况下没有意义,我将与“质量团队”一起解决,以删除此编码规则。请指教。


2
能够ptr == NULL在进行任何操作之前检查是否总是有用的。如果不取消释放指针,则会得到ptr != NULL但仍然无法使用的指针。
KiJéy16年

悬空指针可能导致可利用的漏洞,例如 Use-After-Free
КонстантинВан

Answers:


285

将未使用的指针设置为NULL是一种防御风格,可以防止悬空的指针错误。如果释放了悬空指针,则可以读取或覆盖随机存储器。如果访问了空指针,则在大多数系统上会立即崩溃,并立即告诉您错误是什么。

对于局部变量,如果“很明显”在释放指针后不再访问该指针,可能会毫无意义,因此这种样式更适合于成员数据和全局变量。即使对于局部变量,如果释放内存后函数继续运行,这也是一种好方法。

为了完成样式,您还应该在将指针分配给真指针值之前将其初始化为NULL。


3
我不明白为什么您会“在为指针分配一个真正的指针值之前初始化指向NULL的指针”?
Paul Biggar

26
@Paul:在特定情况下,声明可以读为int *nPtr=NULL;。现在,我同意这将是多余的,在下一行紧跟着一个malloc。但是,如果在声明和第一次初始化之间存在代码,则即使该变量还没有值,也可能有人开始使用该变量。如果您对null进行初始化,则会出现段错误;如果没有,您可能会再次读取或写入随机存储器。同样,如果稍后仅对变量进行有条件的初始化,则如果您记得进行空初始化,则以后的错误访问将使您立即崩溃。
Martin v。Löwis09年

1
我个人认为,在任何平凡的代码库中,对于取消引用null都会出错,而对于取消引用您不拥有的地址也会出错。我个人从不打扰。
wilhelmtell

9
威廉,关键是使用空指针取消引用会导致确定的崩溃和问题的实际位置。错误的访问可能会或可能不会崩溃,并在意外的地方以意外的方式损坏数据或行为。
阿米特·奈杜

4
实际上,初始化指向NULL的指针至少有一个重要的缺点:它可以防止编译器警告您有关未初始化的变量。除非您的代码逻辑实际上明确地为指针处理了该值(即,如果(nPtr == NULL)起作用了...),否则最好保持原样。
埃里克(Eric)

37

设置指向NULL之后的指针free是一种可疑的做法,通常会在明显错误的前提下被普及为“良好编程”规则。这是属于“正确的声音”类别的那些虚假的真理之一,但实际上绝对没有任何用处(有时会导致负面后果)。

据称,将指针设置为NULLafter free可以防止在相同的指针值被free多次传递时避免可怕的“双重释放”问题。但是,实际上,在十分之九的情况下,当使用具有相同指针值的不同指针对象作为的参数时,会发生真正的“双重释放”问题free。不用说,将指针设置为NULLafter free绝对不能防止这种情况下的问题。

当然,当使用相同的指针对象作为to的参数时,可能会遇到“双重释放”问题free。但是,在现实情况中,类似的情况通常表示代码的一般逻辑结构存在问题,而不仅仅是偶然的“双重释放”。在这种情况下,解决此问题的一种正确方法是查看并重新考虑代码的结构,以避免同一指针free多次传递给同一指针的情况。在这种情况下,设置指向NULL并考虑“已解决”问题的指针无非是试图将问题扫到地毯下。在一般情况下,它根本行不通,因为代码结构问题总会找到另一种方式来表现出来。

最后,如果你的代码是专为依靠指针值存在NULL与否NULL,这是完全正常的指针值设置为NULLfree。但是,作为一般的“良好做法”规则(例如,“总是将指针指向” NULL之后free),它再次是众所周知的且毫无用处的伪造品,通常出于纯粹的宗教性,类似伏都教义的原因而经常出现。


1
绝对是 我不记得曾经引起过两次释放,释放后可以通过将指针设置为NULL来解决,但是我已经造成了很多不希望发生的事情。
LnxPrgr3

4
@AnT“可疑”有点多。这完全取决于用例。如果曾经在正确/错误的意义上使用过指针的值,那么这不仅是一种有效的做法,而且是一种最佳做法。
编码员

1
@Coder完全错误。如果以真假的方式使用指针的值来知道在调用free之前是否指向某个对象,那么这不仅是最佳实践,而且是错误的。例如:foo* bar=getFoo(); /*more_code*/ free(bar); /*more_code*/ return bar != NULL;。在这里,在调用barto NULL之后设置为,free将导致该函数认为它从来没有杠,并返回错误的值!
David Schwartz

我认为主要好处不是防止双重释放,而是更早,更可靠地捕获悬空指针。例如,当释放一个包含资源的结构,指向已分配内存的指针,文件句柄等时,当我释放所包含的内存指针并关闭所包含的文件时,我将各自的成员设为NULL。然后,如果错误地通过一个悬空指针访问了其中一个资源,则该程序倾向于每次都在此处出错。否则,如果不使用NULL,释放的数据可能不会被覆盖,并且错误可能不容易重现。
jimhark

1
我同意结构良好的代码不应允许在释放指针之后或两次释放指针的情况下使用指针。但是在现实世界中,我的代码将由可能不认识我并且没有时间和/或技能来正确处理事情的人修改和/或维护(因为截止日期始终是昨天)。因此,我倾向于编写防弹功能,即使使用不当也不会使系统崩溃。
mfloris

34

大多数响应都集中于防止双重释放,但是将指针设置为NULL还有另一个好处。释放指针后,该内存可通过再次调用malloc进行重新分配。如果仍然有原始指针,则可能会遇到一个错误,即在释放并破坏其他变量后尝试使用该指针,然后程序进入未知状态,并且可能发生各种不良情况(如果您很幸运,如果不幸的话,数据损坏。如果在释放后将指针设置为NULL,则以后再尝试通过该指针进行读/写的任何尝试都会导致段错误,通常比随机存储器损坏更可取。

出于两个原因,在free()之后将指针设置为NULL是一个好主意。不过,这并不总是必要的。例如,如果指针变量在free()之后立即超出范围,则没有太多理由将其设置为NULL。


1
+1这实际上是一个很好的观点。不是关于“双重自由”(完全是伪造的)的推理,而是这个。我不是之后的机械指针的空NULL迷free,但这确实是有道理的。
AnT

如果您可以在通过同一指针释放指针之后访问指针,则更有可能在通过其他指针释放指向该对象的对象之后访问指针。因此,这根本对您没有帮助-您仍然必须使用其他某种机制来确保在通过另一个指针释放对象之后,不通过一个指针访问对象。您也可以使用该方法在相同的指针情况下进行保护。
大卫·史瓦兹

1
@DavidSchwartz:我不同意您的评论。几周前,当我不得不为大学练习写一个栈时,我遇到了一个问题,我调查了几个小时。我在某个时候访问了一些已经释放的内存(空闲时间太早了一些)。有时它会导致非常奇怪的行为。如果将指针释放后将其设置为NULL,则将出现“简单”的段错误,并且可以节省几个小时的工作。因此,此答案+1!
mozzbozz 2014年

2
@katze_sonne即使是停下来的时钟也是一天两次。它更可能是指针设置为NULL将隐藏通过防止错误的访问已释放的对象从代码中该段错误为NULL的检查,然后静静地失败,以检查它应该检查的对象错误。(也许在特定的调试版本中释放后将指针设置为NULL可能会有所帮助,或者将它们设置为NULL以外的值(可能会保证段错误)可能是有道理的。但是这种愚蠢的行为曾经对您有所帮助,但这并不是它的支持理由。)
David Schwartz 2014年

@DavidSchwartz好吧,这听起来很合理...感谢您的评论,我以后会考虑的!:) +1
mozzbozz 2014年

20

这是避免覆盖内存的良好做法。在上面的函数中,这是不必要的,但通常在完成后它会发现应用程序错误。

尝试这样的事情:

#if DEBUG_VERSION
void myfree(void **ptr)
{
    free(*ptr);
    *ptr = NULL;
}
#else
#define myfree(p) do { void ** __p = (p); free(*(__p)); *(__p) = NULL; } while (0)
#endif

DEBUG_VERSION使您可以在调试代码中分析释放,但是两者在功能上是相同的。

编辑:添加做...,如下所示,谢谢。


3
如果在不带括号的if语句之后使用宏版本,则该宏版本存在细微的错误。
Mark Ransom

(无效)0是什么?这段代码可以:if(x)myfree(&x); 否则do_foo(); 变成(x){free(*(&x)); *(&x)=空; } void 0; 否则do_foo(); 否则是错误。
jmucchiello

该宏是逗号运算符的理想之地:free((p)),*(p)= null。当然,下一个问题是它将两次评估*(p)。它应该是{void * _pp =(p); 免费(* _pp); * _pp = null; 预处理器不是很有趣。
jmucchiello 2009年

5
宏不应放在括号内,而应放在一个do { } while(0)块中,这样才if(x) myfree(x); else dostuff();不会损坏。
克里斯·卢茨

3
正如Lutz所说,宏主体do {X} while (0)是IMO制作“感觉像和工作似”功能的最佳方法。无论如何,大多数编译器都会优化循环。
Mike Clark

7

如果到达的指针已经被free()d破坏,则可能会中断或不会中断。该内存可能会重新分配到程序的另一部分,然后您会遇到内存损坏的情况,

如果将指针设置为NULL,则如果访问它,则程序始终会因段错误而崩溃。有时它不再起作用,``不再以不可预测的方式崩溃''。它更容易调试。


5
该程序并不总是会因段错误而崩溃。如果访问指针的方式意味着在取消引用之前对其已应用了足够大的偏移量,则它可能会到达可寻址的内存:((MyHugeStruct *)0)-> fieldNearTheEnd。而且甚至在您处理根本不会对0访问进行段错误的硬件之前。但是,该程序更有可能因段错误而崩溃。
史蒂夫·杰索普

7

将指针设置为free'd内存意味着通过该指针访问该内存的任何尝试都将立即崩溃,而不是引起未定义的行为。这样可以更轻松地确定问题出在哪里。

我可以看到您的论点:由于此后nPtr即将超出范围nPtr = NULL,因此似乎没有理由将其设置为NULL。但是,对于struct成员或指针未立即超出范围的其他地方,这更有意义。现在还不应该由不应该使用该指针的代码再次使用该指针。

可能在不区分这两种情况的情况下陈述了该规则,因为自动执行该规则要困难得多,更不用说让开发人员遵循它了。NULL每次空闲后都将指针设置为无害,但是它有可能指出重大问题。


7

c语言中最常见的错误是double free。基本上你做这样的事情

free(foobar);
/* lot of code */
free(foobar);

最终结果很糟糕,操作系统尝试释放一些已经释放的内存,并且通常会出现段错误。因此,好的做法是将设置为NULL,以便您可以进行测试并检查是否确实需要释放此内存

if(foobar != null){
  free(foobar);
}

还需要注意的是,它free(NULL)不会做任何事情,因此您不必编写if语句。我并不是一个真正的操作系统专家,但是即使现在大多数操作系统都会以两次免费使用崩溃。

这也是所有具有垃圾回收功能的语言(Java,dotnet)都以没有出现此问题而自豪,也不必将开发人员整体上留给开发人员而感到自豪的主要原因。


11
实际上,您可以调用free()而不进行检查-free(NULL)被定义为什么都不做。
琥珀色

5
那不是隐藏错误吗?(就像释放过多一样。)
GeorgSchölly09年

1
thanx,我明白了。我尝试过:p = (char *)malloc(.....); free(p); if(p!=null) //p!=null is true, p is not null although freed { free(p); //Note: checking doesnot prevent error here }
Shaobo Wang

5
正如我所说,free(void *ptr) 不能更改它传递的指针的值。它可以更改指针的内容存储在该地址数据,但不能更改地址本身指针。这将需要free(void **ptr)(显然是标准所不允许的)或宏(被允许并且完全可移植,但是人们不喜欢宏)。而且,C并不是为了方便,而是要给程序员尽可能多的控制权。如果他们不想将指针设置为的额外开销NULL,则不应强加于他们。
克里斯·卢茨

2
世界上几乎没有什么东西可以消除C代码作者的专业素养。但是它们包括“在调用之前检查指针是否为NULL free”(以及诸如“广播内存分配函数的结果”或“不考虑使用类型名称与sizeof”之类的东西)。
AnT


4

这实际上很重要。尽管您释放了内存,但是程序的后续部分可能会分配一些新的东西,而这些东西恰好落在了空间中。您的旧指针现在将指向有效的内存块。这样一来,有人可能会使用该指针,从而导致无效的程序状态。

如果使指针为NULL,则使用该指针的任何尝试都会取消引用0x0并立即崩溃,这很容易调试。指向随机存储器的随机指针很难调试。显然没有必要,但这就是为什么它包含在最佳实践文档中。


至少在Windows上,调试版本会将内存设置为0xdddddddd,因此,当您使用指向已删除内存的指针时,便会立即知道。在所有平台上都应该有类似的机制。
i_am_jorf

2
jeffamaphone,在您再次使用指针时,已删除的内存块可能已重新分配并分配给另一个对象。
康斯坦丁

4

根据ANSI C标准:

void free(void *ptr);

free函数使ptr指向的空间被释放,即可以用于进一步分配。如果ptr是空指针,则不执行任何操作。否则,如果参数与calloc,malloc或realloc函数先前返回的指针不匹配,或者如果通过调用free或realloc释放了空间,则该行为是不确定的。

“未定义的行为”几乎总是导致程序崩溃。为了避免这种情况,将指针重置为NULL是安全的。free()本身无法执行此操作,因为仅将其传递给指针,而不传递给指向指针的指针。您还可以编写更安全的free()版本,使指针为NULL:

void safe_free(void** ptr)
{
  free(*ptr);
  *ptr = NULL;
}

@DrPizza-错误(在我看来)是导致您的程序无法正常运行的原因。如果一个隐藏的double free破坏了您的程序,那就是错误。如果它确实按预期工作,那不是错误。
克里斯·卢兹

@DrPizza:我刚刚找到了一个论点,为什么要设置它NULL以避免掩盖错误。stackoverflow.com/questions/1025589 / ...在这两种情况下,似乎都隐藏了一些错误。
GeorgSchölly09年

1
请注意,无效的指针指向有其问题:c-faq.com/ptrs/genericpp.html
确保

3
@Chris,不,最好的方法是代码结构。不要在整个代码库中抛出随机的malloc并释放它们,而将相关的东西放在一起。分配资源(内存,文件等)的“模块”负责释放它,并且还必须提供执行此功能的功能,以便也照料指针。对于任何特定的资源,您将恰好有一个分配资源的地方和一个释放资源的地方,两者都靠在一起。
确保

4
@克里斯·卢茨:霍格沃什。如果编写两次释放同一指针的代码,则程序中将出现逻辑错误。通过使其不崩溃来掩盖该逻辑错误并不意味着该程序是正确的:它仍然在做一些荒谬的事情。在任何情况下,编写双重免费都是没有道理的。
DrPizza

4

我发现这没有什么帮助,因为根据我的经验,当人们访问释放的内存分配时,几乎总是因为他们在某个地方有另一个指向它的指针。然后,它与另一个个人编码标准“避免无用的混乱”相冲突,所以我不这样做,因为我认为它很少有帮助,并且使代码的可读性稍差。

但是-如果不应再次使用指针,则不会将变量设置为null,但通常更高级别的设计使我有理由将其设置为null。例如,如果指针是类的成员,并且我删除了它指向的内容,那么如果您喜欢该类,则“合同”是该成员将随时指向有效的内容,因此必须将其设置为null是因为。区别很小,但我认为很重要。

在c ++中,重要的是在分配内存时始终要考虑谁拥有此数据(除非您使用的是智能指针,但即使那样也需要一些思考)。而且此过程往往导致指针通常是某个类的成员,并且通常您希望某个类始终处于有效状态,而最简单的方法是将成员变量设置为NULL来指示它指向现在什么都没有。

一种常见的模式是在构造函数中将所有成员指针设置为NULL,并在指向您的设计说该类拥有的数据的任何指针上进行析构函数调用删除。显然,在这种情况下,当您删除某些内容以指示您之前不拥有任何数据时,必须将指针设置为NULL。

因此,总而言之,是的,我经常在删除某些内容后将指针设置为NULL,但这是更大设计的一部分,它是关于谁拥有数据的想法,而不是盲目地遵循编码标准规则。在您的示例中,我不会这样做,因为我认为这样做没有任何好处,并且会增加“混乱”,根据我的经验,这种混乱与此类错误和错误代码的产生同样重要。


4

在寻找答案后,最近我遇到了同样的问题。我得出了这个结论:

这是最佳实践,必须遵循此规范才能使其在所有(嵌入式)系统上均可移植。

free()是一个库函数,随着平台的变化而变化,因此您不应期望在将指针传递给该函数并释放内存之后,此指针将被设置为NULL。对于为该平台实现的某些库,情况可能并非如此。

所以总是去

free(ptr);
ptr = NULL;

3

当您尝试避免以下情况时,此规则很有用:

1)您的函数非常长,具有复杂的逻辑和内存管理,并且您不希望稍后在函数中意外地重用指向已删除内存的指针。

2)指针是具有相当复杂行为的类的成员变量,并且您不想在其他函数中意外地将指针重用到已删除的内存。

在您的情况下,这没有什么意义,但是如果功能要更长一些,那可能很重要。

您可能会争辩说,将其设置为NULL可能实际上掩盖了以后的逻辑错误,或者在您假定它有效的情况下,仍然会在NULL上崩溃,因此没关系。

通常,我建议您在您认为这是个好主意时将其设置为NULL,而在您认为不值得时不要打扰。而是专注于编写短函数和设计良好的类。


2

加上其他人所说的,使用指针的一种好方法是始终检查它是否是有效的指针。就像是:


if(ptr)
   ptr->CallSomeMethod();

释放指针后,将其显式标记为NULL即可在C / C ++中使用这种用法。


5
在许多情况下,NULL指针没有意义,因此最好改写一个断言。
Erich Kitzmueller

2

这可能更多是初始化所有指向NULL的指针的参数,但是类似这样的东西可能是一个非常偷偷摸摸的错误:

void other_func() {
  int *p; // forgot to initialize
  // some unrelated mallocs and stuff
  // ...
  if (p) {
    *p = 1; // hm...
  }
}

void caller() {
  some_func();
  other_func();
}

p最终与前者在堆栈中的位置相同nPtr,因此它可能仍包含看似有效的指针。分配给*p可能会覆盖各种不相关的内容,并导致难看的错误。特别是如果编译器在调试模式下将局部变量初始化为零,但是一旦启用优化就不会这样做。因此,在发布版本随机爆炸时,调试版本不会显示任何错误迹象...


2

将刚刚释放的指针设置为NULL不是强制性的,但这是一种好习惯。这样,您就可以避免1)使用释放的指针2)完全释放它


2

设置一个指向NULL的指针是为了再次保护所谓的“双重释放”(double-free),这种情况是针对同一地址多次调用free()而不在该地址上重新分配块。

双重释放导致不确定的行为-通常是堆损坏或立即使程序崩溃。为空指针调用free()不会执行任何操作,因此可以保证安全。

因此,除非您现在确定指针立即或立即在free()之后离开作用域,否则最佳做法是将该指针设置为NULL,以便即使再次调用free(),现在也将使用NULL指针和未定义行为被规避。


2

这个想法是,如果您尝试在释放不再有效的指针后取消对其的引用,则您将要失败(段错误),而不是默默地或神秘地失败。

但小心点。如果取消引用NULL,并非所有系统都会导致段错误。在AIX(至少某些版本)上,*(int *)0 == 0,并且Solaris与此AIX“功能”具有可选兼容性。


2

对于最初的问题:释放代码后立即将指针设置为NULL完全是浪费时间,只要代码满足所有要求,并且已完全调试并且以后将不再修改。另一方面,当有人无意地在free()下添加新的代码块,原始模块的设计不正确时(对于这种情况),以防御性的方式使已释放的指针归零可能会非常有用。 -编译但不执行我想要的错误。

在任何系统中,都有一个无法实现的目标,即最容易做到正确的事情,以及无法减少的不准确测量成本。在C语言中,我们提供了一组非常敏锐,非常强大的工具,这些工具可以在技术工人的手中制造很多东西,如果使用不当,会造成各种隐喻性伤害。有些很难理解或正确使用。人们自然会厌恶风险,因此会进行一些非理性的操作,例如在免费调用它之前检查指针是否为NULL值……

度量问题是,每当您尝试将商品与不良商品区分开时,情况越复杂,您获得歧义测量的可能性就越大。如果目标是仅保留良好做法,那么一些模棱两可的做法就会被实际的不好做法抛弃。如果您的目标是消除弊端,那么歧义可能会与弊端保持一致。这两个目标,仅保持良好或消除明显的劣势,似乎是截然相反的,但通常存在第三者既不是一个也不是另一个,两者都是。

在与质量部门联系之前,请尝试查看错误数据库,以查看无效的指针值多久(如果有的话)导致必须记录下来的问题。如果要真正发挥作用,请确定生产代码中最常见的问题,并提出三种预防方法


好答案。我想补充一件事。出于各种原因,检查错误数据库是件好事。但是,在原始问题的上下文中,请记住,很难知道有多少个无效的指针问题被阻止,或者至少被提早发现而没有进入错误数据库。错误历史记录为添加编码规则提供了更好的证据。
jimhark

2

有两个原因:

避免两次释放时发生崩溃

RageZ在一个重复的问题中撰写。

c语言中最常见的错误是double free。基本上你做这样的事情

free(foobar);
/* lot of code */
free(foobar);

最终结果很糟糕,操作系统尝试释放一些已经释放的内存,并且通常会出现段错误。因此,好的做法是将设置为NULL,以便您可以进行测试并检查是否确实需要释放此内存

if(foobar != NULL){
  free(foobar);
}

还应注意的是 free(NULL) 不会做任何事情,因此您不必编写if语句。我并不是一个真正的操作系统专家,但是即使现在大多数操作系统都会以两次免费使用崩溃。

这也是为什么所有带有垃圾回收的语言(Java,dotnet)都以没有出现此问题而自豪,也不必整体上由内存管理人员来开发而感到自豪。

避免使用已经释放的指针

马丁诉路易斯撰写的另一种答案

将未使用的指针设置为NULL是一种防御风格,可以防止悬空的指针错误。如果释放了悬空指针,则可以读取或覆盖随机存储器。如果访问了空指针,则在大多数系统上会立即崩溃,并立即告诉您错误是什么。

对于局部变量,如果“很明显”在释放指针后不再访问该指针,可能会毫无意义,因此这种样式更适合于成员数据和全局变量。即使对于局部变量,如果释放内存后函数继续运行,这也是一种好方法。

为了完成样式,您还应该在将指针分配给真指针值之前将其初始化为NULL。


1

当您有质量保证团队时,让我补充一点关于质量检查的要点。一些针对C的自动QA工具会将标记的释放指针标记为“对ptr ”。例如,来自Gimpel Software的PC-lint / FlexeLint说 tst.c 8 Warning 438: Last value assigned to variable 'nPtr' (defined at line 5) not used

有一些方法可以有选择地禁止显示消息,因此,如果您的团队决定这样做,您仍然可以满足两个质量检查要求。


1

始终建议使用NULL声明指针变量,例如,

int *ptr = NULL;

假设,ptr指向0x1000内存地址。使用完后free(ptr),建议始终通过再次声明为NULL来使指针变量无效。例如:

free(ptr);
ptr = NULL;

如果未将其重新声明为NULL,则指针变量仍保持指向相同地址(0x1000)的状态,该指针变量称为悬空指针。如果定义另一个指针变量(假设q)并为新指针动态分配地址,则新指针变量可能会占用相同的地址(0x1000)。如果以防万一,您使用相同的指针(ptr)并更新了由相同指针(ptr)指向的地址上的值,则程序最终会将值写入q所指向的位置(因为p0x1000) )。 q为指向相同的地址(

例如

*ptr = 20; //Points to 0x1000
free(ptr);
int *q = (int *)malloc(sizeof(int) * 2); //Points to 0x1000
*ptr = 30; //Since ptr and q are pointing to the same address, so the value of the address to which q is pointing would also change.

1

长话短说:您不想意外(错误地)访问已释放的地址。因为,当您释放地址时,您允许将该堆中的地址分配给其他应用程序。

但是,如果您没有将指针设置为NULL,并且错误地尝试取消引用该指针,或者更改该地址的值;您仍然可以这样做。但是您在逻辑上并不想做。

为什么仍可以访问已释放的内存位置?因为:您可能已经释放了内存,但是指针变量仍然具有有关堆内存地址的信息。因此,作为一种防御策略,请将其设置为NULL。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.