C 无法理解释放内存会引发错误的原因
我正在阅读悬挂指针,发现这样做是一个好习惯,以防止自己出现悬挂指针错误C 无法理解释放内存会引发错误的原因,c,pointers,malloc,free,C,Pointers,Malloc,Free,我正在阅读悬挂指针,发现这样做是一个好习惯,以防止自己出现悬挂指针错误 free(ptr); // free the ptr ptr = NULL; 现在我决定用一个示例香草C代码来测试它 案例1 char *ptr = malloc(10); ... ... free(ptr); ptr=NULL; // Just to check what happen if I call free more than I once free(ptr) ptr=NULL; 一切正常。直到我决定将f
free(ptr); // free the ptr
ptr = NULL;
现在我决定用一个示例香草C代码来测试它
案例1
char *ptr = malloc(10);
...
...
free(ptr);
ptr=NULL;
// Just to check what happen if I call free more than I once
free(ptr)
ptr=NULL;
一切正常。直到我决定将free
和指针NULL
赋值包装在函数中
之前,我将其命名为safefree
void safefree(char *pp) {
free(pp);
pp = NULL;
}
案例2
现在,当我运行上述方法超过1时(如下所示)
我得到以下错误
malloc: *** error for object 0x7fd98f402910: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
我碰巧理解了错误(未分配被释放的指针)
但是我不明白为什么它在案例中没有失败,在示例代码的后半部分失败。首先,让我们回顾一下
free()
的行为。引用第§7.22.3.3章中的C11
free
函数使ptr
指向的空间被释放,即生成
可供进一步分配如果ptr是空指针,则不会发生任何操作。否则,如果
参数与内存管理系统先前返回的指针不匹配
函数,或如果空间已通过调用free
或realloc
解除分配,则
行为未定义。
遵循强调的两点
- 您可以将空指针
传递给null
任意次数,它们都是有效调用(只需忽略)free()
- 无法传递已经传递到
一次的指针free()
free()
之后,我们将显式地将指针设置为NULL
。这就是为什么以后使用相同的指针变量调用free()
,无论调用多少次,都不是问题
案例2:
C使用传递值传递函数参数。这就是为什么,当包装在函数中时
free(pp);
按预期工作(它将所需的指针传递到free()
),但
是函数本地的,并且该更改不会反映到调用方。因此,再次调用该函数会导致双自由,就像现在一样
- 指针已传递到
free()
- 分配的
不会反映给调用方,因此指针不会设置为NULLNULL
- 在下一个调用中,我们将再次传递-
d指针free()
safefree()
的参数,并且从被调用函数中,您可以将指针值设置为NULL
,以使其反映在调用方中。差不多
void safefree(void ** ptrToPtr)
{
free(*ptrToPtr);
*ptrToPtr= NULL;
}
像这样打电话
safefree (&ptrToBeFreed);
将完成这项工作(无论如何,请注意那里的类型)。首先,让我们回顾一下
free()
的行为。引用第§7.22.3.3章中的C11
free
函数使ptr
指向的空间被释放,即生成
可供进一步分配如果ptr是空指针,则不会发生任何操作。否则,如果
参数与内存管理系统先前返回的指针不匹配
函数,或如果空间已通过调用free
或realloc
解除分配,则
行为未定义。
遵循强调的两点
- 您可以将空指针
传递给null
任意次数,它们都是有效调用(只需忽略)free()
- 无法传递已经传递到
一次的指针free()
free()
之后,我们将显式地将指针设置为NULL
。这就是为什么以后使用相同的指针变量调用free()
,无论调用多少次,都不是问题
案例2:
C使用传递值传递函数参数。这就是为什么,当包装在函数中时
free(pp);
按预期工作(它将所需的指针传递到free()
),但
是函数本地的,并且该更改不会反映到调用方。因此,再次调用该函数会导致双自由,就像现在一样
- 指针已传递到
free()
- 分配的
不会反映给调用方,因此指针不会设置为NULLNULL
- 在下一个调用中,我们将再次传递-
d指针free()
safefree()
的参数,并且从被调用函数中,您可以将指针值设置为NULL
,以使其反映在调用方中。差不多
void safefree(void ** ptrToPtr)
{
free(*ptrToPtr);
*ptrToPtr= NULL;
}
像这样打电话
safefree (&ptrToBeFreed);
将完成这项工作(无论如何,注意这里的类型)。除了Jonathan的评论之外,如果你做了导致未定义行为(再次释放指针)的事情,它将导致未定义行为(错误、崩溃)
在不同的上下文中做相同的事情不一定会导致相同的未定义行为,这取决于实现细节;它们通常只为编译器开发人员所知,因此从外部看它们似乎是“随机的”。通过分析随机的未定义行为,我们学不到什么。例如,编译时间可能会影响结果…,或者您所在目录的拼写。。。任何东西。除了Jonathan的评论,如果你做了导致未定义行为(再次释放指针)的事情,它会导致未定义行为(错误、崩溃) 在不同的上下文中做相同的事情不一定会导致相同的未定义行为,这取决于实现