【问题标题】:Facing difficulty to understand Recursion?难以理解递归?
【发布时间】:2014-08-19 06:56:11
【问题描述】:

几天前我遇到了一个问题。 问题来了..

int func(n){
  if(n < 4)
    return func(++n) + func(++n);
  return n;
}

我通过调用func(0) 编译并运行程序,结果为 35。

但我无法可视化堆栈树。

谁能描述堆栈。

【问题讨论】:

  • 认为这是由于排序导致的未定义行为。
  • 另外,为什么不在每次调用开始时使用printf 来显示n?也许还有返回值。这会对你有所帮助。
  • 否 - ++n 不会在这里调用未定义的行为。然而,未指定的行为是计算+ 操作数的顺序。因为它们是相同的,所以没关系。
  • @AlexanderGessler 不,是 UB。两个++ns 是完全无序的。
  • 为什么?编译器必须选择评估func(++n) 的顺序。一旦输入了一个func,它就充当一个序列点,因此n 在计算另一个操作数之前肯定会递增。启发我这种想法有什么问题:-)

标签: c recursion logic


【解决方案1】:

这个问题涉及两个不相关的问题。

编写的代码具有未定义的行为。未指定函数是用 (n+1) 和 (n+2) 调用,还是用 (n+1) 或 (n+2) 调用两次,或者完全是其他东西。标准的相关部分是:C11 n1570 S6.5/2: [EDIT]

如果标量对象的副作用相对于不同的副作用是无序的 在同一标量对象或使用同一标量的值的值计算上 对象,行为未定义。如果有多个允许的排序 一个表达式的子表达式,如果这样一个未排序的边,行为是未定义的 效果发生在任何排序中。 84)

只需对代码稍作改动即可轻松解决此问题,如下所示。

int func(n){
  if(n < 4) {
    return func(n+1) + func(n+2);
  }
  return n;
}

真正的问题是这一切是如何运作的。显然,每个函数都会调用自己两次,或者根本不调用,它只能从最低级别返回 4 或 5。这是二叉树的结构。写出树并标记每个值,您将得到一个由 4s 和 5s 组成的字符串。它们加起来是 35。

【讨论】:

  • “具有实现定义的行为”。不,它没有。它具有未定义的行为。
  • 它具有绝对定义的行为
  • @IVAAAN123 “如果标量对象的副作用相对于同一标量对象的不同副作用或使用相同标量对象的值的值计算是无序的,则行为是 未定义。如果一个表达式的子表达式有多个允许的排序,并且在任何排序中出现这种未排序的副作用,则行为是未定义。” C11 6.5:2
  • @PascalCuoq:谢谢。找不到合适的位。 C++ 标准有类似的措辞。见编辑。绝对是 UB。
  • @PascalCuoq,在 C# 中已定义
【解决方案2】:

就这样吧。

func(1) + func(2)

func(2) + func(3) + func(3) + func(4)


func(3) + func(4) + func(4) + func(5) + func(4) + func(5) + 4

func(4) + func(5) + 4 + 4 +5 +4 + 5 +4

4 + 5 + 4 + 4 +5 +4 + 5 +4

35

【讨论】:

    【解决方案3】:

    有趣(0)

    Stack- fun(1)+fun(2)
    --------------------
    stack- fun(2)+fun(3)+fun(2)
    stack- fun(3)+fun(4)+fun(3)+fun(2)
    stack- fun(4)+fun(5)+fun(4)+fun(3)+fun(2)
    stack- 4+fun(5)+fun(4)+fun(3)+fun(2)
    stack- 4+5+fun(4)+fun(3)+fun(2)
    stack- 9+fun(4)+fun(3)+fun(2)
    

    以此类推,您会发现结果为 35;首先考虑堆栈顶部。

    【讨论】:

      【解决方案4】:

      不同编译器和不同机器的输出可能不同。这就像询问未定义的自动变量的值。

      未定义行为的原因是,在这种情况下,运算符+ 对其操作数没有标准定义的求值顺序。 func(++n)func(n++) 可以先执行。这来源于C语言中序列点的概念。

      【讨论】:

      • 但是这里是func(++n) + func(++n)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-10-09
      • 2016-02-22
      • 1970-01-01
      • 1970-01-01
      • 2016-10-14
      • 2013-09-29
      • 1970-01-01
      相关资源
      最近更新 更多