众所周知,如果我们将一个指针传递给一个函数,它就不能在函数内释放,如下所示:
void func(int *p)
{
free(p);
p = NULL;
}
p持有(可能是有效的)地址的副本,因此free(p)尝试释放它。但由于它是一个副本,它不能真正释放它。对free()的调用如何知道它不能真正释放它?
上面的代码不会产生错误。这是否意味着free()只是默默地失败,“某种程度上”知道作为参数传入的地址无法处理?
答案 0 :(得分:16)
p持有(可能是有效的)地址的副本,因此free(p)尝试释放它。但由于它是一个副本,它无法真正释放它。
这不是真的。如果free()
是p
(或malloc()
)返回的有效地址,NULL
可以正常工作。
实际上,这是实现自定义“析构函数”函数的常见模式(在C中编写OO样式代码时)。
您可能的意思是p
在此之后不会更改为NULL
- 但这很自然,因为您按价值传递了它。如果您希望free()
和将指针置空,则通过指针(“byref”)传递它:
void func(int **p)
{
if (p != NULL) {
free(*p);
*p = NULL;
}
}
并使用此
int *p = someConstructor();
func(&p);
// here 'p' will actually be NULL
答案 1 :(得分:2)
唯一的问题是此函数是否在不同的DLL(Windows)中。然后,它可能与标准库的不同版本链接,并对堆的构建方式有不同的想法。
否则没问题。
答案 2 :(得分:2)
将值p
传递给func()
,这将复制指针并创建本地副本到func()
,从而释放内存。 func()
然后将它自己的指针p
的实例设置为NULL
,但这是无用的。函数完成后,参数p
即将结束。在调用函数时,您仍然有指针p
持有一个地址,但该块现在位于空闲列表中,直到再次分配后才对存储有用。
答案 3 :(得分:1)
每个人都说的是你的记忆将被free(p);
释放,但是你的原始指针(用来调用该函数)仍然会保存(现在无效的)地址。如果在原始指针之后的某个阶段分配了包含您的地址的新内存块将再次变为有效(对于内存管理器),但现在将指向完全不同的数据,从而导致各种问题和混淆。
答案 4 :(得分:0)
不,你真的释放了内存块。在函数调用之后,传递给该函数的指针指向无处:相同的地址但MMU不再知道如何处理该地址