C 在未分配的内存上调用 free

问题描述 投票:0回答:3

为什么这个程序没有崩溃,是不是未定义的行为?

int main()
{
   char* c;
   if (c) {
        printf("called free\n");
        free (c);
   }
   else {
        printf("not called free\n");
   }

   printf("not crashed\n");
   c = strdup("someString");

   if (c) {
        printf("called free\n"); 
        free(c);
        c = NULL;  // why is this needed for last if (c) 
   }
   
   if (c) {
        free(c);
   }
   printf("still not crashed\n");

    return 0;
}
  1. 这个程序有没有可能崩溃?
  2. 在调用 free on char* 之前,我是否应该总是进行这样的 if (c) 验证?
  3. 为什么没有 c=NULL free 被称为?
c pointers undefined-behavior free
3个回答
1
投票

这个程序有没有可能崩溃?

  1. 是的,有。您的代码调用未定义的行为;

行为,使用不可移植或错误的程序构造或 错误数据,为此国际标准强加没有 要求。¹

任何事情都可能发生,包括崩溃。


我是否应该在拨打 free 之前总是进行这样的 if (c) 验证 字符* ?

不,使用

free()
指针常量调用
NULL
是 NOP,即不执行任何操作。所以没必要。

如果 ptr 是空指针,则不会发生任何操作。²


为什么没有 c=NULL free 被称为?

因为

free()
函数没有将原始指针设置为
NULL
c
仍然指向相同的内存位置,但
c
无法再访问它。

free函数使得ptr指向的空间为 释放,即可用于进一步分配。³

如果不将

c
设置为
NULL
,对
free()
的后续调用将释放已经释放的内存,这也会调用未定义的行为。

否则,如果参数与先前返回的指针不匹配 通过内存管理功能,或者如果空间已被释放 通过调用 free 或 realloc,行为未定义。⁴

脚注:

[1] - [2] - [3] - [4] - C11 标准,7.22.3.3

free
函数。


1
投票

这段代码片段

   char* c;
   if (c) {
        printf("called free\n");
        free (c);
   }
   else {
        printf("not called free\n");
   }

调用未定义的行为,因为指针

c
未初始化。

至于这段代码片段

   if (c) {
        printf("called free\n"); 
        free(c);
        c = NULL;  // why is this needed for last if (c) 
   }
   
   if (c) {
        free(c);
   }

那么如果指针

c
不会被设置为
NULL

c = NULL;  // why is this needed for last if (c) 

然后在下一个 if 语句中,将尝试释放已释放的内存,再次调用未定义的行为。

未定义的行为不一定会使程序崩溃。例如,在第一个代码片段中,指针

c
可以在内部设置为
NULL
.

注意你可以为空指针调用函数

free
。在这种情况下,不会发生任何操作。


1
投票

指针值分为三种:

  1. 空指针:因为您显式初始化为 NULL,或者因为它是一个全局(或静态)变量,自动初始化为空指针。
  2. 有效指针:您已明确设置为指向某物的指针:通过使用
    &
    ,或通过调用
    malloc
    realloc
    strdup
    ,只要指针没有变得无效。
  3. 无效指针:未初始化的局部(“自动”)变量的指针;设置(使用
    &
    )指向不再活动的函数(“堆栈框架”)中的局部变量的指针;曾经使用
    malloc
    或其他分配的指针,但后来使用
    free
    释放,或使用
    realloc
    重新分配。

您可以使用普通比较判断指针是否属于类别 1:

if(p == NULL)
if(p != NULL)
.

但关键是没有编程方式来区分类别 2 和 3 中的指针值。也就是没有办法写

if(valid(p))
或者
if(invalid(p))

因此,当您知道指针变量无效时,将指针变量设置为 NULL 是一个好习惯。

© www.soinside.com 2019 - 2024. All rights reserved.