Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/64.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
关于C中的malloc()和free()_C_Pointers_Malloc_Free_Heap - Fatal编程技术网

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

关于C中的malloc()和free(),c,pointers,malloc,free,heap,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;

我有以下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;
}
#包括
#包括
类型定义结构节点
{
INTA;
}节点;
int main()
{
节点*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);
自由(n);
printf(“\n%d\n”,n->a);
n->a=4;
printf(“\n%d\n”,n->a);
返回0;
}
获得的产出是:

1314172

0

六,

0

四,

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

释放是否会使n指向的内存块无效

free(n);
n->a = 4; // is not guaranteed to work, might crash on some implementations
调用未定义的行为

为什么n->a=0,我们如何将其重新分配给n->a=4这样的值

这是因为未定义的行为意味着任何事情都可能发生。你不能相信这一点

附言:不要写这样的代码

编辑

正如所注意到的,您的代码在
free()
之前很久就调用了未定义的行为,然后取消引用
n

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

否,free可能对相关内存执行任何操作,也可能不执行任何操作。但是引用它是无效的。其他进程/您的进程可能已覆盖内存,或者如果您运气不好,数据可能与您留下的数据一样


由您来确定您没有引用空闲内存。

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

在大多数情况下,如果您
释放了一些内存,那么这些内存不会立即重新使用,也不会立即被操作系统回收。这意味着您的应用程序仍然可以访问内存,并且仍然包含其以前的值。您可以经常对其进行读取或写入而不会出错,但您不能依赖此行为


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

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


正如你将来会发现的那样;你最终会经常意外地这样做;通常情况下,坏事情(tm)会发生

重复使用释放的指针类似于为租来的汽车复制钥匙,然后归还汽车,然后在将汽车归还租赁地点后尝试使用钥匙进入汽车。您可能可以侥幸逃脱,但您不应该这样做,而且经常会给您带来麻烦。

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

但是,大多数操作系统除了为应用程序提供所需大小的连续内存块之外,在代表应用程序管理内存方面做得并不多。操作系统也不允许应用程序在MMU中乱搞,因为大多数MMU都不够智能,无法让应用程序安全地运行,而不会对其他程序造成负面影响(无论是意外还是恶意)

因此,当你
malloc()
某个东西时,如果你的应用程序在其现有地址空间中还没有放置位置,它会要求操作系统提供更多,但当你以后
free()
它时,除非它恰好位于你的应用程序地址空间的最末端,当您试图读取内存区域时,不能将其返回给操作系统以使其产生错误


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

大多数操作系统将分配一定的最小空间,该空间将等于或大于您请求的空间。 一旦您呼叫free,此空间将不会返回操作系统,而是保留在您身边以供将来重用。因此,你可以像上面写的那样逃脱惩罚


但严格来说,这属于“未定义”行为。但大多数时候你都可以侥幸逃脱。只是不要养成习惯;)

相关:如果您担心删除数据,那么可以在free()之后在同一个空格上执行calloc……但是,我想这会破坏free的目的:)为什么要使用这种未定义的行为呢?更好的做法是在free()之后将变量设置为NULL。这将确保未定义的行为将成为已定义的行为(崩溃)+1。free()将释放分配的空间,以便通过其他操作重新分配,但不需要清理该内存空间。在你的例子中,我相信在free()之后打印的内容实际上只是先前操作在该内存空间上留下的垃圾;第一个
printf()
取消对未初始化指针的引用。部分不正确。它不必位于应用程序地址空间的“末尾”。例如,在x86上,操作系统可以回收任何对齐的4kB块(“页面”)。虚拟内存的部分用途是对应用程序隐藏这种内存碎片。(实际上,在x86上,操作系统可以从各种页面大小中进行选择,但4kB是最常见的)。虽然硬件和操作系统支持它,但实际上,大多数分配器(例如glibc中的分配器),