【问题标题】:跟踪递归调用
【发布时间】:2022-01-23 15:37:07
【问题描述】:

我正在学习递归的概念,为了实践我的知识,我编写了以下程序。

#include <bits/stdc++.h>

using namespace std;

int c = 0;

int add(int a) {
  if (a == 0) {
    return c;
  }
  c = c + 1;
  add(a - 1);
  cout << "Hello";
}

int main() {
  int x = add(6);
  cout << "Final " << x;
}

它产生了这个输出,这不是我所期望的:

HelloHelloHelloHelloHelloHelloFinal 5134464

为什么当a==0条件满足时程序没有终止,而是将最终结果返回给主函数?

不是那样,而是打印"Hello" 6 次,但输出语句在递归调用之后。

为什么递归调用后的代码还是会执行多次?

我预计它永远不会被执行。

我仍在尝试了解递归的工作原理,所以我想知道这里到底发生了什么。

【问题讨论】:

  • return 表示只从当前函数调用返回,而不是从整个递归堆栈返回。
  • 结果必须是什么?
  • 除了 a 为 0 的情况外,您不会返回任何值。尝试将 add(a-1) 放在末尾并添加这样的返回语句cout…; return add(a-1)
  • 你正在返回c,但你没有保存它
  • 严格来说,您的代码可以打印任何输出,因为不从add 返回值会调用未定义的行为。编译器对此发出警告:godbolt.org/z/81xfPdjdc

标签: c++ recursion output


【解决方案1】:

posted 函数的主要问题是它有undefined behavior

int add(int a) {     // Note that this function is supposed to return an int.
  if (a == 0) {
    return c;        // <- Ok, recursion stopped, first exit point.
  }
  // else 
  c = c + 1;
  add(a - 1);        // Recursive call. When it returns, the execution continue
                     // from here, it does not jump diretly back to main.
                     // That's exactly what would happen if instead of `add`
                     // here, there were a call to another function, say `foo(a-1);`
                     // You would expect the excution to continue after it, don't you?
  cout << "Hello"; 

  // Here a return statement is missing (second exit point) => UB
  // The strange number you see in the output is a result of that. Maybe 
  // return c; 
}

程序执行时你看到的类似于

使用参数 6 调用 add() 使用参数 5 调用 add() 使用参数 4 调用 add() 使用参数 3 调用 add() 使用参数 2 调用 add() 使用参数 1 调用 add() 使用参数 0 调用 add() 返回 0 打印“你好” 返回垃圾(忽略) 打印“你好” 返回垃圾(忽略) 打印“你好” 返回垃圾(忽略) 打印“你好” 返回垃圾(忽略) 打印“你好” 返回垃圾(忽略) 打印“你好” 返回垃圾,存储在 x 打印“Final”以及 x 中的任何内容

【讨论】:

    【解决方案2】:

    拇指规则:递归函数中的返回语句最好是函数的最后一条语句

    你看,你正在返回c,但你没有将它存储在任何地方!

    我相信这是您正在寻找的代码:

    #include <iostream>
    
    void practiceRecursion(const int& a, int& c) {
        if (a != 0) {
            c++;
            practiceRecursion(a-1, c);
        }
    }
    
    int main() {
        int a = 6;
        int c = 0;
        practiceRecursion(a, c);
        // whatever you wish to do with c
        return 0;
    }
    

    【讨论】:

    • 为什么要返回c并将其用作输出参数?
    • 我们可以很容易地完成int num = practiceRecursion(6, 0);(虽然那时我不会使用int&amp;
    • 我不明白你的回答或者你不明白我的问题。我想知道为什么函数 practiceRecursion 有一个输出参数并返回相同的值。所以你把相同的值交还了两次。
    • 啊!哦,对了,不用退货了
    猜你喜欢
    • 1970-01-01
    • 2016-04-13
    • 1970-01-01
    • 2020-04-21
    • 2018-12-31
    • 2010-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多