指针分配给指针和free()如何一起工作?

7
为什么释放指针 p(已分配到另一个指针 q 指向的位置)会同时释放 q?
//for example,
int *p = malloc(sizeof(int));
*p = 10;
int *q = malloc(sizeof(int));
q = p;
free(p);
//This frees q as well.

指针q和p有不同的地址,但只指向相同的位置(即它们存储相同的地址,该地址为10。如果我弄错了,请纠正我)。这种矛盾绝对是由于我对指针的思考方式或free()函数的工作方式产生的,因为根据我的所知(并不多),由于q和p具有不同的地址,释放p不应该对q产生任何影响,除非我在理解指针方面出现了错误,或者free()函数/内存以一种奇特的方式工作。我想知道这是为什么。(我知道这篇文章:释放一个已分配的指针,但它没有解释为什么或如何确切地发生这种情况。)

由于 q = p;,曾经分配给 q 的内存已经“泄漏”了。 - trojanfoe
@trojanfoe,q=p;把p的值(也就是地址10进制表示法的00A1500)赋给了q,对吗?所以如果用盒子来比喻p和q,它们的值都是00A1500,但地址仍然不同。 - Cowgirl
@Cowgirl — 是的,pq 都将包含相同的指针值,但是通过赋值 q = p;,分配给 q 的内存将会丢失。当您调用 free(p); 时,传递给 free() 的是 p 中的值 — 在您的假设中为 0x00A1500,而不是 p 的地址;这与调用 free(q) 相同。您是正确的 — &p != &q,但问题在于存储在这两个单独地址中的值,由于 q = p; 赋值,相同的值存储在两个地址中。 - Jonathan Leffler
如果我写 int x = 10; p=&x; q=p; free(p);, printf("%d",*p);printf("%d",*q); 将会输出有效结果 (10)。 - Cowgirl
关于代码 int *q = malloc(sizeof(int)); q = p;malloc() 函数返回的值将会被覆盖,导致无法恢复的内存泄漏。 - user3629249
2个回答

7

之后

int *p = malloc(sizeof(int));
              x
            +----+
p --------> |    |
            +----+

P指向一些包含垃圾数据的x内存。

*p = 10;

你正在将 10 放入 x 中。
              x
            +----+
p --------> | 10 |
            +----+

以下是相关内容:

int *q = malloc(sizeof(int));
              y
            +----+
q ------->  |    |
            +----+

你创建了一个新的内存 yq 指向该内存。

当你进行赋值时

q = p;
              x
            +----+
p --------> | 10 |
q --------> +----+

              y
            +----+
Memory leak |    |
            +----+

你把指针q也指向了内存x,导致只有的对内存y的引用也失去了。

随着p被释放。

free(p);



p -------->  (invalidated)
q --------> 

              y
            +----+
Memory leak |    |
            +----+

您删除了 x 的内存,因此 pq 指向已释放的内存。


这很有道理。但是如果我写int x = 10; p=&x; q=p; free(p),解引用p和q仍然会得到10。如果我只释放了p会怎样? - Cowgirl
3
这是未定义行为。“free()”不涉及内存所有权,只管理内存。所以,也许你仍然可以访问这块内存且它没有被覆盖 - 也许你会得到一个“segfault(分段错误)”。你只是无法知道。 - 3ch0

4

也许这会有所帮助:

你释放的不是 pq 本身。你释放的是由它们指向的内存块。

free() 后,pq 本身依旧存在。你不能再对它们进行解引用,但你可以在其他方式上继续使用它们。例如,你可以让它们指向另一个有效的地址(之后就可以重新允许对其进行解引用)。


即便如此,我只释放了p而没有释放q。 - Cowgirl
对不起,我现在明白你的观点了。但是如果我写 int x = 10; p=&x; q=p; free(p);printf("%d",*p);printf("%d",*q); 仍然会输出有效结果(10)。 - Cowgirl
@Cowgirl,正如@3ch0上面所说,这是未定义的行为。它能工作是因为同样的位仍然存储在p的前一个地址(释放不会清除内存)。但在这一点上,这已经不再是一个保证了。如果你在释放p之后进行了其他分配,即使你对pq本身没有做任何额外的操作,程序也可以重新使用现在已被释放的内存,并可能用其他值填充这些位。现在,你的打印语句的输出将会改变(除非新存储在那里的位恰好与10的位相同)。 - SO Stinks

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接