众所周知,如果我们将指针按值传递给函数,则它不能在函数内部被释放,如下所示:
void func(int *p)
{
free(p);
p = NULL;
}
p 拥有一个(可能是有效的)地址的副本,因此 free(p) 试图释放它。但由于它是一个副本,它不能真正释放它。对 free() 的调用如何知道它不能真正释放它?
上面的代码不会产生错误。这是否意味着 free() 只是默默地失败,“不知何故”知道无法处理作为参数传入的地址?
众所周知,如果我们将指针按值传递给函数,则它不能在函数内部被释放,如下所示:
void func(int *p)
{
free(p);
p = NULL;
}
p 拥有一个(可能是有效的)地址的副本,因此 free(p) 试图释放它。但由于它是一个副本,它不能真正释放它。对 free() 的调用如何知道它不能真正释放它?
上面的代码不会产生错误。这是否意味着 free() 只是默默地失败,“不知何故”知道无法处理作为参数传入的地址?
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
唯一的问题是该函数是否位于不同的 DLL (Windows) 中。然后,它可能与不同版本的标准库链接,并且对如何构建堆有不同的想法。
否则没问题。
p
按值传递func()
,这将复制指针并创建func()
释放内存的本地副本。func()
然后设置它自己的指针实例,p
但这NULL
是无用的。一旦函数完成,参数p
就结束存在。在调用函数时,您仍然有p
一个保存地址的指针,但是该块现在位于空闲列表中,并且在再次分配之前对存储没有用处。
每个人都在说您的内存将被 释放free(p);
,但您的原始指针(用于调用函数)仍将保存(现在无效的)地址。如果一个新的内存块(包括您的地址)在稍后阶段被分配,那么您的原始指针将再次变为有效(对于内存管理器),但现在将指向完全不同的数据,从而导致各种问题和混乱。
不,你真的释放了内存块。在函数调用之后,传递给该函数的指针不指向任何地方:相同的地址,但 MMU 不再知道如何处理该地址