为啥在使用 malloc() 和 free() 后,两个内存位置会发生变化?
Posted
技术标签:
【中文标题】为啥在使用 malloc() 和 free() 后,两个内存位置会发生变化?【英文标题】:Why might it appear that two memory locations are altered after using malloc() & free()?为什么在使用 malloc() 和 free() 后,两个内存位置会发生变化? 【发布时间】:2014-05-17 11:04:24 【问题描述】:在下面的代码中,我为几个 int 指针分配内存,设置它们的数据,打印数据信息,然后释放它们。然后,我为一个新的 int 指针分配数据并再次打印所有数据。
我观察到的是,相同的数据被写入内存中的新位置以及先前释放的位置之一。我希望它会写入以前释放的位置之一,但为什么它还要写入新位置?
顺便说一句,我正在使用 MS Visual C++ 2010。
代码如下:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv)
int *ip;
int *jp;
int *xp;
printf("\n Memory Allocation Test Bench\n")
printf("----------------------------------\n");
ip = malloc(sizeof(*ip));
jp = malloc(sizeof(void *));
*ip = 10;
*jp = 20;
printf("ip Data: %d, Location: %p\n", *ip, &ip);
printf("jp Data: %d, Location: %p\n", *jp, &jp);
free(ip);
free(jp);
xp = malloc(sizeof(*xp));
*xp = 40;
printf("\nAfter freeing all and setting *xp = 40...\n");
printf("ip Data: %d, Location: %p\n", *ip, &ip);
printf("jp Data: %d, Location: %p\n", *jp, &jp);
printf("xp Data: %d, Location: %p\n", *xp, &xp);
free(xp);
printf("\nAfter freeing xp...\n");
printf("ip Data: %d, Location: %p\n", *ip, &ip);
printf("jp Data: %d, Location: %p\n", *jp, &jp);
printf("xp Data: %d, Location: %p\n", *xp, &xp);
printf("\nPress any key to continue... \n");
getchar();
return EXIT_SUCCESS;
// End of Main
这是我得到的输出,标记显示我在说什么:
您可以看到,当 *xp 设置为 40 时,内存中的两个位置似乎发生了变化。什么可能导致这种情况发生?
更新
在了解到尝试使用已释放的指针是未定义的行为后,我明白不必解释输出,因为导致它的操作是未定义。考虑到这一点,并根据这个问题的答案:What happens to memory after free()?,被释放的指针仍然指向内存中的一个位置,它们只是不应该用于访问它。这引发了关于Setting variable to NULL after free()? 的争论,以首先防止这个问题。
谜团解开
非常感谢Matt McNabb 指出 printf 语句没有打印指针指向的内存中的地址,而是打印指针本身的堆栈地址。像这样替换 printf 行:
printf("xp Data: %d, Location: %p\n", *xp, &xp);
这样的行:
printf("xp Data: %d, Location: %p\n", *xp, xp);
生成了这个新的输出,它清楚地表明一切正常。最后一个 malloc() 语句回收了之前释放的内存。而且由于释放的指针仍然技术上指向内存中的一个有效位置,看起来有两个位置同时被更改:
抛开未定义的行为不谈,这种解释至少可以说明发生了什么 - 一个非常简单(和业余)的编码错误。故事的寓意:记下您正在谈论的地址(堆与堆栈),不要尝试使用已释放的指针访问内存。
【问题讨论】:
您的程序中有多个未定义的行为调用。 不存在数据重复。如果您在调试器中遍历代码,单步执行程序集,您可以解释正在发生的事情。但基本事实是,当您释放缓冲区时,不应再次使用它,因为读取不可靠,写入可能会导致严重问题。 而UB之中,逻辑也是错误的。您正在打印的“位置”是局部变量的地址,与从动态分配返回的地址没有任何关系(如前所述,随后释放并取消引用到行程 UB)。在那里传递的值应该是返回的地址,而不是保存这些地址的指针的地址。例如:printf("ip Data: %d, Location: %p\n", *ip, ip);
&。
使用free
d 的指针是未定义的行为;所有赌注都取消了。
@KurtE.Clothier:您显然不知道“未定义的行为”是对 C 标准的引用,并且一旦您的程序包含 UB,该标准就允许它做任何事情,包括重新格式化硬盘,重新启动计算机等。释放指针后使用指针指向的是 UB。您接受的答案不是一个好答案,因为它忽略了UB。随着您更多地使用 SO,您可能会理解为什么一些老手会这样评论。
【参考方案1】:
没有“两个内存位置被改变”。我猜你说的是输出线:
ip Data: 40, Location: 0012FF60
xp Data: 40, Location: 0012FF3C
但是,您的“位置”不是40
的存储位置;它是指针ip
和xp
的位置(在堆栈上)。要查看存储40
的位置,请输出xp
,而不是&xp
。
此外,您应该将匹配%p
格式说明符的参数强制转换为(void *)
。
尝试打印已释放的指针的值是未定义的行为,更不用说取消引用它了(在这种情况下为ip
或*ip
)。要可靠地打印ip
,请在free
之前执行此操作。
【讨论】:
在“更新”版本中,您会注意到“匹配”值都位于同一地址,即您多次输出同一地址的内容 您的示例表明,当您free
内存和malloc
更多内存时,新分配的内存可能与之前free
d 的内存位于同一位置。以上是关于为啥在使用 malloc() 和 free() 后,两个内存位置会发生变化?的主要内容,如果未能解决你的问题,请参考以下文章