0

我只是对 C 中 free() 函数的行为有一个一般性的问题。

我是否可以假设通过调用free()它只是释放指针指向的内存,但保持指针完好无损?

换句话说,如果我想重用指针,指针不需要重新初始化,只需重新分配内存?

例如,这段代码是否合法?

原版

void foo()
{
    data_t *x;
    int y = 0;

    while(x->data != some_value)
    {
        x = some_function(y);
        y = some_other_function(x);
        free(x);
    }
}

修正版

void foo()
{
    data_t *x;
    int y = 0;

    x = some_function(y);

    while(x->data != some_value)
    {
        y = some_other_function(x);
        free(x);
        x = some_function(y);
    }
}

忽略实际代码(以及 的内部结构data_t)并假设some_function()正确malloc()s x; 我只想知道这是否是管理内存的正确方法,还是data_t *x每次释放后都需要重新初始化?

编辑:我编辑了代码,因为我意识到它没有正确说明我的问题。

4

5 回答 5

2

释放x然后转到下一个while检查将导致未定义的行为

因为在下一次while检查中,你 makewhile(x->data != some_value)并且 x 已经被释放

在进行下一次检查之前,您必须分配x给它的下一个值while

顺便说一句:即使在 while 开始时(在第一次检查中),你也有未定义的行为,因为x在 while 循环之前没有启动到内存区域。


基于问题编辑

free(x)新的情况下没有效果。

当您释放xx 指针时,保留 x 指向的旧内存地址,但不再分配内存,它是空闲的。

当您在释放后将新分配的内存分配给 x 时,x 将指向新的内存区域

于 2013-10-10T06:35:47.433 回答
1

是的,修改后的代码版本是管理内存的正确方法。无需再次重新初始化 x。只是您需要确保在释放 x 之后,永远不要使用它。但是,您可以再次为其重新分配一些内存并使用它。

于 2013-10-10T07:16:27.743 回答
1

根据 ISO C 标准中的抽象语言定义,在调用free来自分配器的有效非空指针后,该指针的值变为indeterminate。对该值的任何使用都是未定义的行为。不确定的值不能再次变为有效。

在 C 的实际实现中,保留在程序中的不确定指针值可以在不检测的情况下传递和评估,并且当内存被回收到新分配的对象时,它们变得与有效指针无法区分,从而导致各种问题。

这并不违反规范,因为任何行为都属于未定义行为的范畴。

如果您编写的程序运行可靠,但依赖于通过内存分配恢复的这种悬空指针,则该程序根据 ISO C 定义不明确,并且不太可能根据您的编译器或操作进行良好定义系统文档。

编译后的程序今天可以工作,但明天,你的 malloc 代码libc.so会更新,因此内存的回收方式不同,它会中断。

测试程序是否产生预期的行为很重要,但这不是完整的故事。行为还必须依赖于语言规范、系统和工具文档的某些保证,否则,某种合理的推理可以让您对程序的正确运行负责。

后者的一个例子是,有时我们可以在语言级别滥用 C 编译器以获得一些所需的机器代码。虽然这不是由 ISO C 定义的,甚至可能不是由您的编译器开发人员定义的,但是一旦您拥有机器代码,那么从某种意义上说,您如何获得它并不重要;可以独立检查它是否符合您的要求。您可以对此负责,并设置回归保护措施,以监控该代码是否存在不需要的更改(当编译器以不同方式操作,或升级或其他情况时)。

malloc您不能轻易地对和的行为承担这种责任free,它是一个运行时黑盒,其行为可以在程序部署很久之后在现场发生变化。

于 2013-10-10T07:25:16.310 回答
1

它只是释放指针指向的内存,但保持指针完好无损?

没错。如果 free() 在其他方面是一个普通的 C 函数,它就不会影响你传递给它的指针值。由于 C 按值传递参数,因此 free() 会收到您传递给它的指针的副本,并且它不能更改您原来的 x 指针。(它当然可以改变 x 指向内容)

换句话说,如果我想重用指针,指针不需要重新初始化,只需重新分配内存?

free(x);
x = some_function(y);

这正是你在这里所做的,你将 x 分配给其他东西,所以这就是通常会做的事情。指针包含一个地址,您为其分配另一个地址。

这与以下概念相同:

 int x 
 x = function_that_returns_int();
 x = function_that_returns_int();

如果您只需为 分配一个新值i,则在为其分配新值之前无需执行任何其他操作i

于 2013-10-10T07:18:27.483 回答
0

while 条件检查无效,因为 x 没有指向任何分配的内存。所以它会导致一些垃圾值。但是,如果代码进入 while 循环,x 被分配了一些内存,然后它被释放。所以 x 现在变成了一个悬空指针。在接下来的同时检查它也会包含一些垃圾值。如果指针试图访问属于其他进程的某些数据,它在某些情况下甚至会导致分段错误。

于 2013-10-10T07:12:21.090 回答