该程序如何打印10个语句?

时间:2011-10-06 11:39:13

标签: c++ recursion

该程序以递归方式调用函数tester

#include <iostream>
 void tester();
 int i = 1;
 int k = 1;

 int main() {
   tester();
 }

 void tester() {
  while(i++ < 10)
    tester();
  std::cout << "called " << k++ << " times" << std::endl;
 }

我对此输出感到惊讶:

called 1 times
called 2 times
called 3 times
called 4 times
called 5 times
called 6 times
called 7 times
called 8 times
called 9 times
called 10 times

这是因为这是我理解这个程序的方式

首次从主调用测试人员后,它进入循环。循环的第一个语句再次调用函数tester,并继续执行。循环10次后,while循环之后的语句应该,即只有一次。所以输出应该是:called 1 times。但这实际上并没有发生!为什么?该计划如何运作?

4 个答案:

答案 0 :(得分:2)

while正文在每个递归深度中只执行一次。当whilei时,10为false,这将是递归调用tester () 10次的时间。由于i已声明为全局,i++每次调用都会显示tester ()更新。

while条件为false时的最后一个递归深度,最后一次tester ()调用将返回其先前的深度。此时,while循环的下一次迭代将为false,因为i10。在每个cout循环终止后将遇到while语句,它将依次打印k的值,在递归回滚时递增每个递归深度。

手动追踪会发生什么事情来理解这些东西。

<强>更新

查看执行输出。特别要注意d参数,它表示递归深度。在每个深度,while循环迭代一次,直到最后“,而为真,测试人员称为”输出。在深度10处,while为假,因为它是10,并且第一次将控件返回到其先前的深度级别(i10时的第一次“返回” )。返回后,控件返回到最后一级的while循环的主体,从中调用该函数(刚从中返回),并且该循环的下一次迭代将为false,(i是全局和10或更多),因此这也返回。类似地,在每个递归深度处,while循环的第二次迭代为假,并且它一直返回。检查输出。

i   k  d
 1  1  0, call from main
 2  1  1, while is true, tester called
 3  1  2, while is true, tester called
 4  1  3, while is true, tester called
 5  1  4, while is true, tester called
 6  1  5, while is true, tester called
 7  1  6, while is true, tester called
 8  1  7, while is true, tester called
 9  1  8, while is true, tester called
10  1  9, while is true, tester called
11  1 10, returning back, print k    // this step the while is false in depth 10
12  2  9, returning back, print k    // from now on, as the recursion rolls back
13  3  8, returning back, print k    // the second iteration at each recursive 
14  4  7, returning back, print k    // depth will be executed, and each while
15  5  6, returning back, print k    // condition will be false, therefore it will
16  6  5, returning back, print k    // not call tester anymore and return the control
17  7  4, returning back, print k    // to the previous level. NOICE the `d' parameter
18  8  3, returning back, print k
19  9  2, returning back, print k
20 10  1, returning back, print k

这是测试代码。我希望现在描述清楚(?)。分析这将有所帮助。

#include <stdio.h>

int i = 1;
int k = 1;

void tester (int d)
{
  while (i++ < 10)
  {
    printf ("%2d %2d %2d, while is true, tester called\n", i, k, d);
    tester (d+1);
  }
  printf ("%2d %2d %2d, returning back, print k\n", i, k++, d);
}

int main (void)
{
  int depth = 0;
  printf ("i   k  d\n");
  printf ("%2d %2d %2d, call from main\n", i, k, depth);
  tester (depth + 1);

  return 0;
}

答案 1 :(得分:2)

测试执行十次,所以cource std :: cout也被使用了十次。

由于递归,测试者的最后一次调用首先返回,因此打印顺序实际上与调用顺序相反。

编辑: 尝试这个代码,也许它可以帮助你理解(对不起,它不是很漂亮,只是快速破解):

#include <iostream>
void tester();
void print_indent(int cnt);
int i = 1;
int k = 1;
int recursion_level = 0;
int call_num = 0;

int main() {
    tester();
}

void tester() {
    int my_call = call_num++;
    print_indent(recursion_level);
    std::cout << "start of tester " << my_call << std::endl;
    recursion_level++;
    while(i++ < 10)
        tester();
    print_indent(recursion_level);
    std::cout << "called " << k++ << " times" << std::endl;
    recursion_level--;
    print_indent(recursion_level);
    std::cout << "end of tester " << my_call << std::endl;
}

void print_indent(int cnt) {
    for (int i = 0; i < cnt; i++)
        std::cout << "  ";
}

答案 2 :(得分:1)

一旦启动递归调用 ,当前函数将冻结,直到该调用返回 。所以你的函数首先进行递归调用,然后打印。

所以第一次打印将在名为latest的函数中出现。一旦最新的被叫函数打印 并返回 ,所有先前的调用将开始打印并返回,直到最早的被调用函数退出。

答案 3 :(得分:1)

这是递归的本质。当tester()调用自身时,它会构建一堆调用,然后在每个函数返回时打印消息。每次测试人员返回时,都会打印消息,由于while循环,该消息将发生10次。 我把它想象成这样:

i    k    
---  ---  ---
 1    1  + tester()
 2    1  |   + tester()
 3    1  |   |   + tester()
 4    1  |   |   |   + tester()
 5    1  |   |   |   |   + tester()
 6    1  |   |   |   |   |   + tester()
 7    1  |   |   |   |   |   |   + tester()
 8    1  |   |   |   |   |   |   |   + tester()
 9    1  |   |   |   |   |   |   |   |   + tester()
10    1  |   |   |   |   |   |   |   |   |   + tester()
11    1  |   |   |   |   |   |   |   |   |   + "called 1 times"
12    2  |   |   |   |   |   |   |   |   + "called "2" times"
13    3  |   |   |   |   |   |   |   + "called 3 times"
14    4  |   |   |   |   |   |   + "called 4 times"
15    5  |   |   |   |   |   + "called 5 times"
16    6  |   |   |   |   + "called 6 times"
17    7  |   |   |   + "called 7 times"
18    8  |   |   + "called 8 times"
19    9  |   + "called 9 times"
20   10  + "called 10 times"