在我的测试中,我发现在free()之后可以使用指针.我有以下代码:
typedef struct{
int module_id;
int adc_id;
struct config_line * pnext;
} config_line;
config_line * create_list()
{
config_line * phead = (config_line *) malloc(sizeof(config_line));
phead->pnext=NULL;
phead->module_id = 1;
phead->adc_id = 2;
printf("module_id=%d adc_id=%d\n",phead->module_id, phead->adc_id);
free(phead);
printf("module_id=%d adc_id=%d\n",phead->module_id, phead->adc_id);
phead->module_id = 2;
phead->adc_id = 5;
printf("module_id=%d adc_id=%d\n",phead->module_id, phead->adc_id);
}
Run Code Online (Sandbox Code Playgroud)
此代码的输出是:
module_id=1 adc_id=2
module_id=0 adc_id=2
module_id=2 adc_id=5
Run Code Online (Sandbox Code Playgroud)
为什么在free(phead)之后我可以访问(读写)指针?为什么没有分段错误?
Lih*_*ihO 12
当你调用时free(phead),内存phead指向被释放,但是phead不变的值保持不变,成为phead一个悬空指针.访问已释放的内存会产生未定义的行为.
NULL一旦释放它指向的内存,分配给指针是一个好习惯:
free(phead);
phead = NULL;
Run Code Online (Sandbox Code Playgroud)
鸡的头被砍掉了,为什么还能继续跑跳?请注意,这并不总是发生;有些鸡可能会立即停止活动,而另一些鸡可能会继续奔跑数月。当它确实发生时,它会发生,因为它发生了。这是否意味着我们应该砍掉宠物的头?
就像砍掉我们宠物的头一样,使用已释放的内存是一个坏主意。这并不意味着它会产生负面结果;您的程序可能会继续在您的计算机上按预期运行,而if (fubar)(其中fubar是您的无效指针)可能足以导致您的程序在其他实现上出现故障。
这种实现定义(或不定义)行为的自由思想正式称为未定义行为;该行为是未定义的,因为 C 标准(一组规定 C 实现应如何行为的文档)没有定义该行为。因此,就像砍掉宠物的头一样,我们应该避免所有不确定的行为。
因为内存仍映射到您的进程中,但未分配。C程序中有两个级别的内存管理:首先,内核为您提供了可以写入的页面。如果该进程需要更多已映射的内存,则它必须向内核(sbrk)请求更多。但是,这需要很大的块,因此malloc为您将其切成块,根据需要请求更多的页面,但要使用已分配给程序的可能内存。在释放使用该页面的所有分配之前,free无法返回该页面。
因此,内核给您的内存访问冲突(SIGSEGV)相当粗略,并且无法处理大多数内存错误,只有从内核角度来看这是致命的事情。您可以随意破坏malloc的跟踪数据,可以在大多数分配结束之后读取数据,也可以在许多释放之后读取数据,等等。
但是永远不要提交内存错误。使用使用非常严格的VM的valgrind运行您的应用程序,以检查所有错误并立即消除它们。
因为释放内存(指针)只是将该内存放回到空闲内存池中。内存不会消失,并且直到再次分配并写入该内存时,它的内容才会被清除。
因此,在内存被释放后,很可能对其进行访问。只是不像你想象的那样是一个好主意,因为它可以随时分配和修改。
| 归档时间: |
|
| 查看次数: |
6596 次 |
| 最近记录: |