关于C中的malloc()和free()

时间:2010-09-20 17:11:53

标签: c pointers malloc free heap

我有以下C代码:

#include<stdio.h>
#include<stdlib.h>

typedef struct node
{
    int a;
}node;

int main()
{
    node * n;

    printf("\n%d\n",n->a);

    n  = (node *) malloc ( sizeof( node ));

    printf("\n%d\n",n->a);
    n->a = 6;
    printf("\n%d\n",n->a);
    free(n);
    printf("\n%d\n",n->a);
    n->a = 4;
    printf("\n%d\n",n->a);
    return 0;
}

获得的输出是:

1314172

0

6

0

4

我的问题是在free(n)之后,为什么n-> a = 0 我们如何将它重新分配给任何值,如n-> a = 4 ?

不自由使n指向的内存块无效??

7 个答案:

答案 0 :(得分:15)

free(n);
n->a = 4; // is not guaranteed to work, might crash on some implementations

调用未定义的行为。

  

为什么n-> a = 0,我们如何将它重新分配给任何值,如n-> a = 4?

多数民众赞成因为未定义的行为意味着任何事情都可能发生。你不能依赖它。

P.S:不要写这样的代码。

编辑

由于Jonathan注意到您的代码在您free()之前很久就会调用未定义的行为,然后取消引用n

node * n; //n is not initialized
printf("\n%d\n",n->a);  //dereferencing a wild pointer invokes UB.

答案 1 :(得分:13)

重复使用已释放的指针类似于为您租用的汽车制作钥匙的副本,返回汽车,然后在您将汽车返回租赁地点后尝试使用该钥匙进入汽车。你可能能够逃脱它,但你不应该这样做,而且经常会让你遇到麻烦。

答案 2 :(得分:4)

不,免费可能会或可能不会对相关内存做任何事情。但是引用它是无效的。其他进程/您的进程可能已经覆盖了内存,或者如果您运气不好,数据可能就像您离开时一样。

由您来确保您不参考免费记忆。

答案 3 :(得分:4)

取消引用指向未分配内存的指针时,行为未定义。这意味着它可以做任何事情。它可能会触发错误,或者可能会执行其他操作。

在大多数情况下,如果您free有一些内存,则该内存不会立即重复使用,并且不会立即被操作系统回收。这意味着应用程序仍可访问内存,并且仍将包含其先前的值。您经常可以正确地阅读或写信,但您不能依赖此行为

如果您在许多不同的环境中运行此代码,您会发现在某些环境中它始终有效,在某些环境中它总是会触发错误,但在许多其他环境中它会“大部分时间”起作用。这使得C很难调试! :)

答案 4 :(得分:1)

释放内存块。这并不意味着你不能写信给它;这意味着你不能写信给它。机器不会阻止你这样做(通常,有一些工具,如电围栏,将阻止它)

你将来会发现;你最终会意外地做这件事;并且通常会发生坏事(tm)

答案 5 :(得分:0)

在大多数针对具有MMU的硬件(例如x86)的操作系统上,实际获取内存读取错误的唯一方法是应用程序地址是否未映射。由于MMU没有一个条目告诉它在物理内存中找到与应用程序所要求的逻辑地址相关联的数据,它会导致中断并且操作系统接管,对其进行一些操作。

但是大多数操作系统代表应用程序管理内存并没有太大作用,只是给它一个连续的所需大小的内存块。操作系统也不允许应用程序在MMU中进行清理,因为大多数MMU都不够聪明,不能让应用程序安全地做事情而不会对其他程序产生负面影响(无论是偶然还是恶意)。

所以当你malloc()某事时,如果你的应用程序还没有地方可以把它放在现有的地址空间中,它会向操作系统询问更多内容,但是当你稍后free()它时,除非恰好位于应用程序的地址空间的最后,否则当您尝试读取时,不能将其返回给操作系统以使该内存区域导致错误。

有一些方法可以实现这一点,例如mmap(),但这并不是使用该功能的正确理由。

答案 6 :(得分:0)

大多数操作系统将分配一个最小空间,该空间将等于或大于您请求的空间。 一旦您免费拨打电话,此空间将不会返回操作系统,而是与您保持一致,以备将来重用。因此,你可以摆脱上面所写的东西。

但严格来说,这被归类为“未定义”行为。但是你可以在大多数时候逃脱它。只是不要养成习惯;)