C的这种行为如何解释?

时间:2012-08-21 21:28:34

标签: c recursion decrement

所以我正在玩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?

5 个答案:

答案 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--) + xfoo(--x) + x的子表达式的评估顺序。让我们考虑第一个包含表达式

的程序
foo(--x) + x

如果按以下(有效!)顺序评估子表达式,则程序具有未定义的行为:

    读取
  1. x以计算x的值作为+的右侧操作数,

  2. 读取
  3. x以计算x的值作为--的操作数,

  4. x用于在递减后存储新值x

  5. foo被称为

  6. 此处唯一的序列点是在步骤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)调用它,所以它永远不会接近零,这就是原因。