4

我认为一旦函数返回,其中声明的所有局部变量(除了带有static关键字的变量)都会被垃圾收集。但是当我尝试下面的代码时,它仍然会在函数返回后打印值。谁能解释为什么?

int *fun();
main() {
  int *p;
  p = fun();
  printf("%d",*p); //shouldn't print 5, for the variable no longer exists at this address
}
int *fun() {
  int q;
  q = 5;
  return(&q);
}
4

5 回答 5

7

C 中没有垃圾收集。一旦变量的范围不再存在,以任何方式访问它都是非法的。你看到的是UB(未定义的行为)。

于 2012-10-15T18:05:06.433 回答
6

这是未定义的行为,任何事情都可能发生,包括看起来有效。内存可能还没有被覆盖,但这并不意味着您有权访问它。然而你做到了!我希望你快乐!:)

于 2012-10-15T18:04:51.240 回答
4

如果您真的希望它释放该值,则可以在通过访问该位置执行 printf 之前调用另一个包含至少几行代码的函数。到那时,您的价值很可能会被覆盖。

但再次如前所述,这是未定义的行为。您永远无法预测它何时(或是否有)崩溃或变化。但是您不能依赖它“更改或保持不变”并使用任何这些假设编写应用程序。

我要说明的是,当您从前一个函数返回后进行另一个函数调用时,另一个激活记录被推送到堆栈中,很可能会覆盖前一个记录,包括您通过指针访问其值的变量。

一旦一个函数和它的数据超出范围,实际上没有身体是垃圾收集或做一个说 memset 0 。

于 2012-10-15T18:08:03.340 回答
2

C 不支持 Java 所支持的垃圾回收。在此处阅读有关垃圾收集的更多信息

于 2012-10-15T18:10:03.513 回答
1

逻辑上,退出 q时不复存在。fun

物理上(对于“物理”的适当松散定义),故事有点复杂,并且取决于底层平台。C 不进行垃圾收集(在这种情况下不适用垃圾收集)。占用的内存单元(虚拟或物理)q仍然存在,并且包含最后写入的任何值。根据架构/操作系统/其他情况,您的程序可能仍然可以访问该单元格,但这不能保证:

6.2.4 对象的存储期限

2 对象的生命周期是程序执行期间保证为其保留存储的部分。一个对象存在,具有一个常量地址,33) 并在其整个生命周期中保留其最后存储的值。34) 如果一个对象在其生命周期之外被引用,则该行为是未定义的。当指针指向(或刚刚过去)的对象到达其生命周期的末尾时,指针的值变得不确定。
33) 术语“恒定地址”意味着在可能不同时间构造的两个指向对象的指针将比较相等。在同一程序的两次不同执行期间,地址可能不同。

34) 在 volatile 对象的情况下,最后的存储不需要在程序中明确显示。

“未定义的行为”是 C 语言通过不处理问题来处理问题的方式。基本上,实现可以自由地以它选择的任何方式处理这种情况,直到完全忽略问题并让底层操作系统杀死程序做一些顽皮的事情。

在您的特定情况下,退出后访问该存储单元fun不会破坏任何内容,并且尚未被覆盖。不能保证该行为是可重复的。

于 2012-10-15T18:50:19.313 回答