C 释放后将变量设置为NULL
在我的公司有一条编码规则,规定释放内存后,将变量重置为C 释放后将变量设置为NULL,c,coding-style,malloc,free,heap-memory,C,Coding Style,Malloc,Free,Heap Memory,在我的公司有一条编码规则,规定释放内存后,将变量重置为NULL。例如 void some_func () { int *nPtr; nPtr = malloc (100); free (nPtr); nPtr = NULL; return; } 我觉得,在类似上面显示的代码的情况下,设置为NULL没有任何意义。还是我遗漏了什么 如果在这种情况下没有任何意义,我将与“质量团队”讨论删除此编码规则。请给出建议。这背后的想法是停止意外重用释放的指针。将
NULL
。例如
void some_func ()
{
int *nPtr;
nPtr = malloc (100);
free (nPtr);
nPtr = NULL;
return;
}
我觉得,在类似上面显示的代码的情况下,设置为NULL
没有任何意义。还是我遗漏了什么
如果在这种情况下没有任何意义,我将与“质量团队”讨论删除此编码规则。请给出建议。这背后的想法是停止意外重用释放的指针。将指针设置为
空闲'd内存意味着任何通过指针访问该内存的尝试都将立即崩溃,而不是导致未定义的行为。这使得确定哪里出了问题变得更加容易
我可以看到你的论点:因为nPtr
在nPtr=NULL
之后就超出了范围,所以似乎没有理由将其设置为NULL
。但是,对于struct
成员或指针没有立即超出范围的其他地方,它更有意义。不应该使用该指针的代码是否会再次使用该指针,目前还不清楚
很可能规则是在没有区分这两种情况的情况下陈述的,因为自动执行规则要困难得多,更不用说让开发人员遵循规则了。在每次空闲后将指针设置为空并不有害,但它有可能指出大问题。将未使用的指针设置为空是一种防御方式,可以防止指针出现悬空错误。如果悬空指针在释放后被访问,则可以读取或覆盖随机内存。如果访问空指针,大多数系统会立即崩溃,并立即告诉您错误是什么
对于局部变量,如果“明显”指针在释放后不再被访问,则可能有点毫无意义,因此这种样式更适合于成员数据和全局变量。即使对于局部变量,如果函数在释放内存后继续,也可能是一个好方法
要完成该样式,您还应该在指针被指定一个真正的指针值之前将指针初始化为NULL。这(可能)实际上很重要。虽然您释放了内存,但程序的后续部分可能会分配一些新的内容,这些内容碰巧会降落在空间中。您的旧指针现在将指向一个有效的内存块。然后可能有人会使用指针,导致程序状态无效
如果将指针设为NULL,那么任何使用它的尝试都将取消引用0x0并在那里崩溃,这很容易调试。指向随机内存的随机指针很难调试。这显然不是必需的,但这就是为什么它会出现在最佳实践文档中。这被认为是避免覆盖内存的良好实践。在上面的函数中,这是不必要的,但通常在完成后会发现应用程序错误
请尝试以下方法:
#if DEBUG_VERSION
void myfree(void **ptr)
{
free(*ptr);
*ptr = NULL;
}
#else
#define myfree(p) do { void ** p_tmp = (p); free(*(p_tmp)); *(p_tmp) = NULL; } while (0)
#endif
DEBUG_版本允许您在调试代码中分析空闲,但两者在功能上是相同的
编辑:添加了do。。。正如下面所建议的,谢谢。如果您到达已释放的指针()d,它可能会断开或不断开。内存可能会被重新分配到程序的另一部分,然后导致内存损坏
如果将指针设置为NULL,那么如果访问它,程序总是会因segfault而崩溃。不再,有时它工作“”,不再,以不可预测的方式崩溃“”。这更容易调试。当您试图避免以下情况时,此规则非常有用:
1) 您有一个非常长的函数,具有复杂的逻辑和内存管理,您不希望在函数的后面意外地重用指向已删除内存的指针
2) 指针是具有相当复杂行为的类的成员变量,您不希望意外地在其他函数中重用指向已删除内存的指针
在您的场景中,这没有多大意义,但如果函数变长,可能会有影响
您可能会争辩说,将其设置为NULL实际上可能会在以后掩盖逻辑错误,或者在您假设它有效的情况下,仍然会在NULL上崩溃,所以这无关紧要
一般来说,当你认为这是一个好主意时,我建议你将它设置为NULL,当你认为它不值得时,不要麻烦。相反,要专注于编写简短的函数和设计良好的类。要补充其他人所说的内容,使用指针的一个好方法是始终检查它是否是有效的指针。比如:
if(ptr)
ptr->CallSomeMethod();
释放指针后将其显式标记为NULL允许在C/C++中使用这种用法。这可能更像是一个将所有指针初始化为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
可能会覆盖所有不相关的内容并导致丑陋的bug。特别是如果编译器在调试模式下使用零初始化局部变量,但在启用优化后不进行初始化。因此,当发布版本随机爆炸时,调试版本不会显示任何错误迹象…c中最常见的错误是双自由。基本上你是这样做的
free(foobar);
/* lot of code */
free(foobar);
结果非常糟糕,操作系统试图释放一些已经释放的内存,通常会出错。因此,最好将设置为NULL
,这样您就可以进行测试并检查是否确实需要释放此内存
if(foobar != null){
free(foobar);
}
if(foobar != NULL){
free(foobar);
}
还要注意的是,free(NULL)
不会做任何事情,因此您不必编写if语句。我并不是一个真正的操作系统大师,但即使是现在,大多数操作系统都会因双重免费而崩溃
这也是一个主要的问题
void safe_free(void** ptr)
{
free(*ptr);
*ptr = NULL;
}
free(foobar);
/* lot of code */
free(foobar);
if(foobar != NULL){
free(foobar);
}
free(ptr);
ptr = NULL;
int *ptr = NULL;
free(ptr);
ptr = NULL;
*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.