3

当我运行此代码时:

#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

虽然我已经释放了食物。为什么是这样?内存真的释放了吗?

4

7 回答 7

10

当你释放“食物”时,你是在说你已经吃完了。但是,指针 food 仍然指向相同的地址,并且该数据仍然存在(在不需要时必须将释放的每一位内存都归零会产生太多开销)

基本上这是因为它是一个如此小的例子,它有效。如果在 free 和 print 语句之间有任何其他 malloc 调用,那么您可能不会看到这一点,并且很可能会以某种可怕的方式崩溃。你不应该依赖这种行为。

于 2010-06-02T17:40:52.810 回答
3

没有什么比得上免费的食物了 :) 当你“免费”一些东西时,这意味着同一个空间再次准备好被其他东西使用。这并不意味着用垃圾填满它。其次,指针值没有改变——如果你正在认真编码,你应该在释放指针后将指针设置为 NULL,这样就不会发生像这样的潜在垃圾访问。

于 2010-06-02T17:44:04.377 回答
2

释放内存并不一定会覆盖它的内容。

于 2010-06-02T17:37:26.483 回答
2

sizeof是一个编译时操作,所以内存分配不会改变它的工作方式。

free不会擦除内存,它只是将块标记为未使用。即使你分配了几百兆的内存,你的指针可能仍然不会被覆盖(现代计算机有很多RAM)。但是,释放内存后,您就不能再依赖它的值了。

看看你的开发环境是否有内存分配调试设置——有些设置可以用类似于0xDEADBEEF你的时候覆盖块的设置free

此外,您可能希望养成NULL在调用后立即将指针设置为的习惯free(以帮助鼓励您的程序尽早且大声崩溃)。

于 2010-06-02T17:46:44.807 回答
1

free告诉内存分配器它可以重用该内存块,仅此而已。它不会用零或任何东西覆盖块 - 幸运的是,因为这可能是一个非常昂贵的操作!它所做的是使指针的任何进一步取消引用未定义,但“未定义”行为很可能意味着“做与以前相同的事情” - 你不能依赖它。在另一个编译器、另一个 runime 或在其他条件下,它可能会抛出异常、终止程序或损坏其他数据,所以......只是不要。

于 2010-06-02T17:48:00.347 回答
1

在 C 中没有“结构有数据”或“结构没有数据”之类的东西。在你的程序中,你有一个指向内存某处的指针。只要此内存属于您的应用程序(即未返回到系统),它将始终包含某些内容。那个“东西”可能完全是垃圾,或者看起来或多或少有意义。此外,内存可能包含看似有意义的垃圾(先前存储在那里的数据的剩余部分)。

这正是您在实验中观察到的。一旦你释放了这个结构,它以前占用的内存就正式包含了垃圾。但是,这些垃圾可能仍然类似于存储在该结构对象中的原始数据的点点滴滴,在它被释放的那一刻。在您的情况下,您很幸运,因此数据看起来完好无损。不过不要指望它——下一次它可能会被完全摧毁。

就 C 语言而言,您正在做的事情构成了未定义的行为。不允许检查已释放的结构是否“有数据”。您所问的“为什么”问题在 C 语言领域并不存在。

于 2010-06-02T17:50:08.090 回答
0

在某些系统中,释放内存会将其从地址空间中取消映射,如果您在取消分配内存后尝试访问它,您将获得核心转储或等效内容。

在 win32 系统中(至少通过 XP) ,情况并非如此。微软特意在 32 位 Windows 上制作了内存子系统,以保持与众所周知的在释放内存后使用内存的 MS-DOS 应用程序的兼容性。

在 MS-DOS 编程模型中没有映射或进程空间的概念,因此这些类型的错误直到在 Windows95 下作为 DOS 模式程序执行时才显示为程序故障。

这种行为在 32 位 Windows 中持续了十多年。现在它可能会改变,因为在 Vista 和 7 等系统中正在取消旧版兼容性。

于 2010-06-02T17:45:02.927 回答