#include <stdio.h>
#include <stdlib.h>
int * alloc()
{
int *p = (int *)calloc(5,4);
printf("%d\n",p);
return p;
}
int main()
{
int *p = alloc();
free(p);
printf("%d\n",p);
p[0] = 1;
p[1] = 2;
printf("%d %d\n",p[0],p[1]);
}
至于代码段,我先分配5个整数。然后我释放了记忆。 当我打印p时,为什么p sill的值与首先分配的内存地址相同? 我也可以为p [0]和p [1]赋值。这是否意味着free()什么都不做?有一次,我 分配内存,我可以稍后使用虽然我已经释放它。
答案 0 :(得分:13)
免费不什么也不做。它将内存释放回分配器,因此可以再次使用内存。
你在做什么调用未定义的行为。您的程序可能出现,但稍后可能会崩溃。
答案 1 :(得分:13)
free
在该地址释放内存。它不会更改p
变量本身。但是,在此之后使用p
执行任何操作都是未定义的行为。如果你在释放后立即使用它似乎可行,但它仍然完全错误,可能导致崩溃或更糟。
free
是特定于实现的。但是,在大多数实现中,它将写入堆中的簿记数据,以指示内存现在可用。例如,它可能将特定块标记为未使用,或者将块与相邻的空块组合。
请注意,使用%d
作为指针也是未定义的。
答案 2 :(得分:9)
只能以页面为单位从程序中删除内存,即使这样也不太可能被观察到。
如果需要,calloc(3)和malloc(3)与内核进行交互以获取内存。但是大多数free(3)的实现都没有将内存返回到内核 1 ,它们只是将它添加到一个空闲列表中,calloc()和malloc()稍后会参考,以便重用已释放的块
即使free()想要将内存返回给系统,它也需要至少一个连续的内存页才能让内核真正保护该区域,因此释放一个小块只会导致保护更改如果它是页面中的 last 小块。
所以你的街区就在那里,坐在免费清单上。您可以像访问它一样访问它。 C直接编译为机器代码,没有特殊的调试安排,对负载和存储没有健全性检查。现在,如果您尝试访问一个空闲块,标准就不会定义该行为,以免对库实现者提出不合理的要求。有各种各样的事情可能会出错:
1。很少有free()实现尝试将内存返回系统的事实不一定是由于实现者的松弛。与内核交互比简单地执行库代码慢得多,而且好处很小。大多数程序具有稳态或增加的内存占用,因此分析堆寻找可返回内存所花费的时间将被完全浪费。其他原因包括内部碎片使页面对齐的块不太可能存在,并且返回块可能会将块分块到任何一方。最后,少数几个返回大量内存的程序可能会绕过malloc()并简单地分配和释放页面。
答案 3 :(得分:4)
从技术上讲
p[0] = 1;
p[1] = 2;
当您尝试使用 dangling pointer p
时,调用未定义的行为(这意味着任何)。
此外,即使printf("%d\n",p);
调用UB(格式说明符的不匹配和printf()
中的参数类型),也是迂腐的
答案 4 :(得分:3)
逻辑思考。
调用free(ptr),告诉系统,ptr引用的先前内存现在是免费的。
这意味着,系统可以根据需要使用内存。并且相信我,系统会很快或者稍后将自己的数据写入同一个地址,覆盖您的数据,或者同样的事情将在您的多任务操作系统中执行另一个程序。
您可能会问为什么ptr具有相同的值? 嗯,答案很简单:速度。 系统不知道您是否打算在免费通话后立即为ptr分配一个新的有效地址,或者您只是将其弃用。
在任何情况下,最好在免费调用之后立即为ptr指定一个NULL指针:
free(ptr);
ptr = NULL;
因为在您的功能/模块/程序的另一部分,您将能够检查:
if(NULL == ptr){
/* ... */
}
顺便说一句,如果你以某种方式在相同的地址上免费拨打两次,你的程序将崩溃 - 这是在免费通话后进行NULL分配的另一个好理由,因为免费(NULL) - 是安全的操作:
free(ptr);
ptr = NULL; /* try to comment out/put back this line and see what happens */
free(ptr);
在复杂的程序中,它可能会发生。
答案 5 :(得分:2)
free()实际上是释放内存。但是,它对指针没有任何作用。实际上,在C语言中,您可以尝试写入任何内存位置。没有安全检查(超出段错误,如果您尝试访问程序区域外的内存,则会导致程序崩溃)。但是,这并不意味着尝试使用已发布和/或未初始化的内存是个好主意。这是一个内存错误。你会变得讨厌他们。 :)
答案 6 :(得分:2)
free
被定义为将malloc
和朋友分配的内存返回给系统。实际发生的情况在不同系统上有所不同。以下事情可能发生:
printf
可能会将某些内存用于某些内部目的,或者可能不会 - 取决于实现。实际上发生了哪些事情,取决于您在调用free
之后及之后的确切时刻C库的实现和系统状态。但有一点应该是明确的 - 你应该永远在以任何方式调用free
之后使用内存。它可能会崩溃,它可能不会崩溃,但它永远不会好。
要抓住这种情况 - 在free
之后使用内存 - 有许多程序。在Linux中,最受欢迎的是valgrind
。