5

众所周知,如果我们将指针按值传递给函数,则它不能在函数内部被释放,如下所示:

void func(int *p)
{
    free(p);
    p = NULL;
}

p 拥有一个(可能是有效的)地址的副本,因此 free(p) 试图释放它。但由于它是一个副本,它不能真正释放它。对 free() 的调用如何知道它不能真正释放它?

上面的代码不会产生错误。这是否意味着 free() 只是默默地失败,“不知何故”知道无法处理作为参数传入的地址?

4

5 回答 5

21

p 拥有一个(可能是有效的)地址的副本,因此 free(p) 试图释放它。但由于它是一个副本,它不能真正释放它。

这不是真的。如果(或)返回的有效地址free()可以正常工作。pmalloc()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
于 2012-12-18T17:20:27.243 回答
2

唯一的问题是该函数是否位于不同的 DLL (Windows) 中。然后,它可能与不同版本的标准库链接,并且对如何构建堆有不同的想法。

否则没问题。

于 2012-12-18T17:21:46.653 回答
2

p按值传递func(),这将复制指针并创建func()释放内存的本地副本。func()然后设置它自己的指针实例,p但这NULL是无用的。一旦函数完成,参数p就结束存在。在调用函数时,您仍然有p一个保存地址的指针,但是该块现在位于空闲列表中,并且在再次分配之前对存储没有用处。

于 2012-12-18T17:28:02.887 回答
1

每个人都在说您的内存将被 释放free(p);,但您的原始指针(用于调用函数)仍将保存(现在无效的)地址。如果一个新的内存块(包括您的地址)在稍后阶段被分配,那么您的原始指针将再次变为有效(对于内存管理器),但现在将指向完全不同的数据,从而导致各种问题和混乱。

于 2012-12-18T17:50:41.077 回答
0

不,你真的释放了内存块。在函数调用之后,传递给该函数的指针不指向任何地方:相同的地址,但 MMU 不再知道如何处理该地址

于 2012-12-18T17:21:37.293 回答