所以我正在玩C中的递归,我不知道为什么会发生这种情况:
代码A
int foo(int x)
{
if (x==0) return 0;
else return foo(--x)+x;
}
int main() { printf("%d\n", foo(10));
代码B
int foo(int x)
{
if (x==0) return 0;
else return foo(x--)+x;
}
int main() { printf("%d\n", foo(10));
代码A打印45而不是55,我想出来了。这是因为递归调用以这种方式解开:9+8+7+...+0 = 45
另一方面,代码B卡住了,永远不会返回提示!我必须ctrl+c
。为什么会卡住?是因为它从未减少过10?
答案 0 :(得分:9)
那是因为在片段中,在递归调用后,x x会递减,因此总是使用foo(10)调用该函数
修改强>
正如James McNellis在其评论中指出的那样,x在调用函数之前会减少,但是它的原始值会在调用中使用,而不是在递减时使用。
基本上表达式x--在foo(x--)之前被计算,但它的值实际上是x,因此函数被调用x = 10
答案 1 :(得分:2)
后递减(x--)
等待函数调用在执行之前返回。所以你的堆栈看起来像:
foo(10)
foo(10)
foo(10)
...
答案 2 :(得分:1)
在存储值递减之前,表达式x--
的值是x
的当前值。因此,在调用foo(x--)
时,foo
的参数值始终与其当前值相同,从而产生无限递归。
但请注意,两个程序的行为可能未定义,并且取决于foo(x--) + x
和foo(--x) + x
的子表达式的评估顺序。让我们考虑第一个包含表达式
foo(--x) + x
如果按以下(有效!)顺序评估子表达式,则程序具有未定义的行为:
x
以计算x
的值作为+
的右侧操作数,
x
以计算x
的值作为--
的操作数,
x
用于在递减后存储新值x
foo
被称为
此处唯一的序列点是在步骤3和步骤4之间:在计算参数表达式之后,在调用函数之前。因为x
被读取两次(在[1]和[2]中)并且被写入一次(在[3]中)并且因为其中一个读取(在[1]中)不是为了计算新值要存储,行为是未定义的。
评估顺序是未指定,但如果此评估顺序是使用的顺序,则程序具有未定义的行为。
同样的理由同样适用于第二个程序。
最好使用x - 1
作为foo
的参数,因为此表达式不会修改x
的值。
答案 3 :(得分:0)
是的,它永远不会减少。
else return foo(x--)+x;
在你调用你的函数的行中,你使用一个postdecrement,这意味着值10首先被传递给你的下一个函数,之后,它会递减 - 这从未发生,因为没有函数返回
答案 4 :(得分:0)
调用
foo(--x)
使用已经减少的值调用函数,而
foo(x--)
总是用原始值(即10)调用它,所以它永远不会接近零,这就是原因。