【问题标题】:What does free do to a pointer passed by value to a function?free 对按值传递给函数的指针有什么作用?
【发布时间】:2012-12-05 23:14:08
【问题描述】:

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

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

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

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

【问题讨论】:

  • 嗯...这样就可以了。当然,传递给函数的指针不会为 NULL,但内存会被释放。
  • StackOverflow 经验法则 #3:如果 OP 说“已知”,则不是。
  • 不会释放内存,但是要将原始指针设置为空,您需要指针本身的地址,而不是指针的副本。

标签: c pointers memory-management


【解决方案1】:

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

这不是真的。如果p 是malloc()(或NULL)返回的有效地址,free() 可以正常工作。

事实上,这是实现自定义“析构函数”函数的常见模式(在 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

【讨论】:

    【解决方案2】:

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

    否则没问题。

    【讨论】:

    • 什么意思,完全没有?
    • 哦,但它是 - 我也解释了原因。
    • 不,抱歉,不正确。标准库的版本与此无关。
    • 您可以多次说“它不正确”,但它不会改变任何东西。请重新阅读我的答案以了解标准库版本的重要性,您将能够避免伤害许多业余爱好者的危险陷阱。
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-11-26
          • 1970-01-01
          • 2018-08-25
          • 2018-06-02
          • 1970-01-01
          相关资源
          最近更新 更多