当我运行此代码时:
#include <stdio.h>
typedef struct _Food
{
char name [128];
} Food;
int
main (int argc, char **argv)
{
Food *food;
food = (Food*) malloc (sizeof (Food));
snprintf (food->name, 128, "%s", "Corn");
free (food);
printf ("%d\n", sizeof *food);
printf ("%s\n", food->name);
}
我还是
128
Corn
虽然我已经解放了食物。为什么是这样?记忆真的被释放了吗?
答案 0 :(得分:10)
当你释放“食物”时,你说你完成了它。但是,指针食物仍然指向相同的地址,并且该数据仍然存在(将不必要时释放的每一位内存归零都是太多开销)
基本上是因为它是一个很小的例子,这是有效的。如果在free和print语句之间有任何其他malloc调用,那么你可能不会看到这个,并且很可能会以某种糟糕的方式崩溃。你不应该依赖这种行为。
答案 1 :(得分:2)
释放内存不一定会覆盖它的内容。
答案 2 :(得分:2)
没有像免费食物:) 当你“释放”某些东西时,它意味着同样的空间再次准备被其他东西使用。这并不意味着用垃圾填满。 其次,指针值没有改变 - 如果你正在认真编码,你应该在释放它之后将指针设置为NULL,这样就不会发生像这样的潜在垃圾访问。
答案 3 :(得分:2)
sizeof
是一个编译时操作,因此内存分配不会改变它的工作方式。
free
不会擦除内存,只是将块标记为未使用。即使你分配了几百兆的内存,你的指针仍然可能没有被覆盖(现代计算机有很多的RAM)。但是,在释放内存后,您将无法再依赖其值。
查看您的开发环境是否具有内存分配调试设置 - 有些设置可以在0xDEADBEEF
时使用free
覆盖块。
此外,您可能希望在调用NULL
后立即设置指针free
的习惯(以帮助鼓励您的程序提前和大声崩溃)。
答案 4 :(得分:1)
free
告诉内存分配器它可以重用那个内存块,没有别的。它不会用零或任何东西覆盖块 - 幸运的是,因为这可能是一个非常昂贵的操作! 所做的做的是使指针的任何进一步解除引用未定义,但“未定义”行为很可能意味着“做与以前相同的事情” - 你不能依赖它。在另一个编译器,另一个runime,或在其他条件下,它可能会抛出异常,或终止程序,或破坏其他数据,所以...只是不要。
答案 5 :(得分:1)
C中没有“struct have data”或“struct not data”这样的东西。在你的程序中,你有一个指向内存中某处的指针。只要此内存属于您的应用程序(即未返回到系统),它将始终包含某些内容。那些“东西”可能是完全垃圾,或者看起来或多或少有意义。此外,内存可能包含看似有意义的垃圾(以前存储在那里的数据的剩余部分)。
这正是您在实验中观察到的。一旦你解除了分析结构,以前被它占用的内存正式包含垃圾。但是,该垃圾可能仍然类似于在解除分配时存储在该结构对象中的原始数据的位。在你的情况下你很幸运,所以数据看起来完好无损。不要指望它 - 下次它可能会完全被摧毁。
就C语言而言,您正在做的是构成未定义的行为。您不能检查解除分配的结构是否“有数据”。你问的“为什么”问题并不存在于C语言领域。
答案 6 :(得分:0)
在某些系统中,释放内存会将其从地址空间中取消映射,如果在取消分配后尝试访问它,您将获得核心转储或等效内容。
在win32系统中(至少通过XP),这是不的情况。微软在32位Windows上制作他们的内存子系统故意使内存块保持不变,以保持与释放后使用内存的众所周知的MS-DOS应用程序的兼容性。
在MS-DOS编程模型中,没有映射或进程空间的概念,因此这些类型的错误在Windows95下作为DOS模式程序执行之前不会显示为程序失败。
这种行为在32位Windows上持续了十多年。现在可能会改变,因为Vista和7等系统中的旧版兼容性已被撤销。