Mar*_*kon 2 c malloc free gcc memory-management
我对C中的内存管理(以及Debian GNU/Linux下的GCC 4.3.3)提出了疑问.
根据K&R的C编程语言书(第7.8.5节),当我释放指针然后取消引用它时,是一个错误.但是我有些怀疑,因为我注意到有时候,就像我在下面粘贴的源代码一样,编译器(?)似乎按照定义明确的原则工作.
我有一个像这样的简单程序,它显示了如何返回动态分配的数组:
#include <stdio.h>
#include <stdlib.h>
int * ret_array(int n)
{
int * arr = (int *) malloc(10 * sizeof(int));
int i;
for (i = 0; i < n; i++)
{
arr[i] = i*2;
}
printf("Address pointer in ret_array: %p\n", (void *) arr);
return arr;
}
int * ret_oth_array(int n)
{
int * arr = (int *) malloc(10 * sizeof(int));
int i;
for (i = 0; i < n; i++)
{
arr[i] = i+n;
}
printf("Address pointer in ret_oth_array: %p\n", (void *) arr);
return arr;
}
int main(void)
{
int *p = NULL;
int *x = NULL;
p = ret_array(5);
x = ret_oth_array(6);
printf("Address contained in p: %p\nValue of *p: %d\n", (void *) p, *p);
free(x);
free(p);
printf("Memory freed.\n");
printf("*(p+4) = %d\n", *(p+4));
printf("*x = %d\n", *x);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果我尝试用一些参数编译它:-ansi -Wall -pedantic-errors它不会引发错误或警告.不只; 它也运行良好.
Address pointer in ret_array: 0x8269008
Address pointer in ret_oth_array: 0x8269038
Address contained in p: 0x8269008
Value of *p: 0
Memory freed.
*p+4 = 8
*x = 0
Run Code Online (Sandbox Code Playgroud)
*(p + 4)为8,*x为0.为什么会发生这种情况?如果*(p + 4)是8,则x不应该是6,因为x数组的第一个元素是6?
如果我尝试将调用顺序更改为free,则会发生另一件奇怪的事情.例如:
int main(int argc, char * argv[])
{
/* ... code ... */
free(p);
free(x);
printf("Memory freed.\n");
printf("*(p+4) = %d\n", *(p+4));
printf("*x = %d\n", *x);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
实际上在这种情况下输出(在我的机器上)将是:
*p+4 = 8
*x = 142106624
Run Code Online (Sandbox Code Playgroud)
为什么x指针真正被"释放",而p指针被释放(我希望)"不同"?好吧,我知道在释放内存后我应该指向指向NULL,但我只是好奇:P
qrd*_*rdl 13
它是未定义的行为,因此将freed指针作为一个错误,因为奇怪的事情可能(并且会发生).
free()所以它一直指向进程地址空间堆不改变指针的值-这就是为什么你没有得到段错误,但它没有指定在某些平台上的理论,当你尝试,你可以得到段错误在取消后立即取消引用指针free.
为了防止这种情况,将指针指向NULL之后是一个好习惯,free因此它会以可预测的方式失败 - 段错误.
请注意,在某些操作系统(HP-UX,也可能是其他操作系统)上,允许取消引用NULL指针,只是为了防止段错误(从而隐藏问题).我发现它相当愚蠢,因为它使诊断起来更加困难,尽管我不知道这背后的全部故事.
Ces*_*arB 10
free()(和malloc())不是来自gcc.它们来自C库,在Debian上通常是glibc.所以,你看到的是glibc的行为,而不是gcc(并且会随着不同的C库或不同版本的C库而改变).
我特别是,你使用后free()你正在释放内存块malloc()给你.它不再是你的了.由于它不应再被使用,glibc中的内存管理器可以随心所欲地对内存块做任何事情,包括使用它的一部分作为自己的内存结构(这可能是你看到它的内容发生变化的原因;它们已经被簿记信息覆盖,可能会指向其他区块或某种类型的计数器).
还有其他事情可以发生; 特别是,如果你的分配大小足够大,glibc可以向内核请求一个单独的内存块(带mmap()或类似的调用),并在期间将其释放回内核free().在这种情况下,您的程序将崩溃.理论上,这也可能在某些情况下发生,即使分配很少(glibc可以增加/缩小堆).
这可能不是您正在寻找的答案,但无论如何我都会试一试:
既然你正在玩未定义的行为,你永远不应该以任何方式,形状或形式依赖它,它有什么好处才能知道一个给定的实现究竟是如何处理的呢?
由于gcc可以在任何给定时间,版本,架构之间或根据月球的位置和亮度自由改变处理,因此在了解它如何处理它时没有任何用处.至少不是使用gcc的开发人员.
| 归档时间: |
|
| 查看次数: |
1321 次 |
| 最近记录: |