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()
    一次的指针
案例1: 这里,在使用指针调用
free()
之后,我们将显式地将指针设置为
NULL
。这就是为什么以后使用相同的指针变量调用
free()
,无论调用多少次,都不是问题

案例2: C使用传递值传递函数参数。这就是为什么,当包装在函数中时

free(pp);
按预期工作(它将所需的指针传递到
free()
),但

是函数本地的,并且该更改不会反映到调用方。因此,再次调用该函数会导致双自由,就像现在一样

  • 指针已传递到
    free()
  • 分配的
    NULL
    不会反映给调用方,因此指针不会设置为NULL
  • 在下一个调用中,我们将再次传递-
    free()
    d指针
如前所述,这将调用

解决方案:您需要传递一个指向指针的指针作为被调用函数
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()
    一次的指针
案例1: 这里,在使用指针调用
free()
之后,我们将显式地将指针设置为
NULL
。这就是为什么以后使用相同的指针变量调用
free()
,无论调用多少次,都不是问题

案例2: C使用传递值传递函数参数。这就是为什么,当包装在函数中时

free(pp);
按预期工作(它将所需的指针传递到
free()
),但

是函数本地的,并且该更改不会反映到调用方。因此,再次调用该函数会导致双自由,就像现在一样

  • 指针已传递到
    free()
  • 分配的
    NULL
    不会反映给调用方,因此指针不会设置为NULL
  • 在下一个调用中,我们将再次传递-
    free()
    d指针
如前所述,这将调用

解决方案:您需要传递一个指向指针的指针作为被调用函数
safefree()
的参数,并且从被调用函数中,您可以将指针值设置为
NULL
,以使其反映在调用方中。差不多

void safefree(void ** ptrToPtr) 
{ 
     free(*ptrToPtr); 
     *ptrToPtr= NULL; 
 }
像这样打电话

 safefree (&ptrToBeFreed);

将完成这项工作(无论如何,注意这里的类型)。

除了Jonathan的评论之外,如果你做了导致未定义行为(再次释放指针)的事情,它将导致未定义行为(错误、崩溃)


在不同的上下文中做相同的事情不一定会导致相同的未定义行为,这取决于实现细节;它们通常只为编译器开发人员所知,因此从外部看它们似乎是“随机的”。通过分析随机的未定义行为,我们学不到什么。例如,编译时间可能会影响结果…,或者您所在目录的拼写。。。任何东西。

除了Jonathan的评论,如果你做了导致未定义行为(再次释放指针)的事情,它会导致未定义行为(错误、崩溃)

在不同的上下文中做相同的事情不一定会导致相同的未定义行为,这取决于实现