我写了一个简单的程序来测试free()之后动态分配的内存的内容,如下所示。 (我知道我们不应该在免费后访问内存。我写了这个来检查免费后内存中会有什么内容)
#include <stdio.h>
#include <stdlib.h>
main()
{
int *p = (int *)malloc(sizeof(int));
*p = 3;
printf("%d\n", *p);
free(p);
printf("%d\n", *p);
}
输出: 3 0
我认为它会打印垃圾值或第二次打印声明崩溃。但它总是打印0。
1)此行为是否依赖于编译器?
2)如果我尝试使用free()两次释放内存,则会生成核心转储。在手册页中,提到程序行为异常。但我总是得到核心转储。这种行为是否还取决于编译器?
答案 0 :(得分:3)
free()
是否删除动态分配的内存中存储的数据?
没有。 free
只释放其参数(指针)指向的已分配空间。此函数接受指向先前分配的内存块的char指针,并释放它 - 也就是说,将其添加到可重新分配的可用内存块列表中。
释放的存储器不会以任何方式清除/擦除。
你不应该取消引用释放(悬空)指针。标准说:
[...]否则,如果参数与先前由内存管理返回的指针不匹配 函数,或者如果通过调用
free
或realloc
释放了空格,则行为未定义。
上面的引用还指出,释放指针两次将调用未定义的行为。一旦UB运行,您可能会得到预期的意外结果。可能存在程序崩溃或核心转储。
答案 1 :(得分:3)
如gnu网站所述
释放块会改变块的内容。在释放它之后,不要期望在块中找到任何数据(例如指向块链中下一个块的指针)。
因此,释放后访问内存位置会导致未定义的行为,尽管free不会更改内存位置中的数据。在这个例子中,你可能会得到0
,你可能会在其他一些例子中得到垃圾。
并且,如果你试图释放内存两次,在第二次尝试时你会试图释放一个未分配的内存,这就是为什么你要进入核心转储。
答案 2 :(得分:0)
就标准C而言,它没有被指定,因为它是不可观察的。只要你free
内存,指向那里的所有指针都是无效的,所以无法检查那个内存。 *)
即使你碰巧有一些标准的C库记录某种行为,你的编译器仍然可能会认为指针在传递给free
后没有被重用,所以你仍然不能指望任何特定的行为。
*)我认为,即使阅读这些指针也是UB,不仅是解除引用,而且无论如何这都无关紧要。
答案 3 :(得分:0)
除了以上关于use-after-free语义的所有解释之外,你真的可能想要调查每个C程序员的生命保护程序:valgrind。它会自动检测代码中的此类错误,并且通常会将您的隐藏在现实世界中。 Coverity和所有其他静态代码检查器也很棒,但valgrind很棒。