我在练习基本的C问题时偶然发现了这段代码:
int func(num) {
if (num > 0) {
return (num + func(num - 2));
}
}
int main() {
printf("%d\n", func(5));
return 0;
}
代码在执行时返回8作为答案。但我认为答案应该是“无法确定”。
我脑海中的递归调用看起来像这样:
5 + func(3) => 5 + (3 + func(1))
3 + func(1) => 3 + (1 + func(-1))
1 + func(-1) => 1 + (?)
对于?
符号,我认为阅读func(-1)
的返回值是未定义的行为。我是基于assumption,对于func(-1)
,没有显式的int值被返回。因此,在我看来,从表达式(1 + func(-1))
中的func(-1)
阅读应该会产生一些garbage result + 1
。
为什么代码返回的答案是8,而不是垃圾?
当我显式地向func
传递一个负数并读取结果时,我确实得到了垃圾值,例如下面的代码;
int main() {
printf("%d\n", (1 + func(-1))); // returns garbage result and not 0
return 0;
}
为什么在递归调用中(1 + func(-1))
被赋值为0?
我在一台64位机器上用gcc编译代码为gcc myfile.c
。编译代码asgcc -W -Wall -ansi -pedantic myfile.c
给出了关于func
函数的警告,但这不是重点。我不知道8是什么答案。
2条答案
按热度按时间a11xaf1n1#
为什么在递归调用一个行为未定义的函数时不返回垃圾值?
因为“垃圾”并不是你所想的那样。特别是,“垃圾”并不意味着“随机”。(或者如果是这样,它更像是xkcd 221。
计算机通常是确定性的。你必须非常努力才能获得真正的随机行为。即使是一个包含最糟糕的未定义行为的程序,每次运行它时,也会经常返回完全相同的奇怪和不确定的数字。
我用了这个类比:
假设你去商店买了一个全新的垃圾桶。但它是完全干净的!一点垃圾都没有!它是如此干净,你可以吃了它!这是虚假广告吗?商店是否欺骗性地卖给你一个非垃圾桶?
查看以上问题的更多讨论:12345。(其中大多数都在谈论未初始化的局部变量的值,而不是未能执行正确的
return
语句的函数的值,但参数是相同的。llmtgqce2#
如果一个C实现遵守C标准的所有适用规则,那么它就符合C标准。
C标准将术语“未定义”定义为“本文档不强加任何要求”(C 2018 3.4.3)。
当一个函数在其关闭
}
处终止而没有返回值,但程序试图使用返回值时,该行为是未定义的(C 2018 6.9.1 12)。这意味着对行为没有要求。因此,对于您所展示的代码,没有对行为的要求,因此程序符合C标准的所有规则,无论它输出什么或是否打印任何东西。
特别是,C标准并不禁止程序打印“8”,也不要求程序打印一个奇怪的或大的数字,或者在你看来像“垃圾”的数字。