了解啤酒瓶示例中的递归

我自己在C中练习递归,我在网上找到了这个例子。 但有一件事我不明白。

void singSongFor(int numberOfBottles) { if (numberOfBottles == 0) { printf("There are simply no more bottles of beer on the wall.\n\n"); } else { printf("%d bottles of beer on the wall. %d bottles of beer.\n", numberOfBottles, numberOfBottles); int oneFewer = numberOfBottles - 1; printf("Take one down, pass it around, %d bottles of beer on the wall.\n\n", oneFewer); singSongFor(oneFewer); // This function calls itself! // Print a message just before the function ends printf("Put a bottle in the recycling, %d empty bottles in the bin.\n", numberOfBottles); } } 

然后我使用main方法:

  int main(int argc, const char * argv[]) { singSongFor(4); return 0; } 

输出如下:

墙上有4瓶啤酒。 4瓶啤酒。 拿下一个,将它传递,墙壁上有3瓶啤酒。

墙上有3瓶啤酒。 3瓶啤酒。 拿一个,将它传递,墙上有2瓶啤酒。

墙上有2瓶啤酒。 2瓶啤酒。 拿一个,将它传递,墙上放一瓶啤酒。

墙上有1瓶啤酒。 1瓶啤酒。 拿下一个,将它传递到墙上,0瓶啤酒。

墙上根本没有更多的啤酒瓶。

将一个瓶子放入回收处,在垃圾箱中放入一个空瓶子。

将一个瓶子放入回收处,在垃圾箱中放入2个空瓶子。

将一个瓶子放入回收箱中,在垃圾箱中放入3个空瓶子。

将一个瓶子放入回收箱中,将4个空瓶放入垃圾箱。

我非常了解第一部分,直到我来到“墙上再也没有啤酒瓶了。之后我不明白可变数量的瓶子从1增加到4。

请注意,最后一个printf使用numberOfBottles变量,并且永远不会修改它。 因此,从打印一个oneFewer瓶子返回后,它将打印带有numberOfBottles的回收文本。 请记住,每次调用函数时,局部变量都有一个不同的化身。

如果缩进对函数的调用,则可以更容易地看到:

 4 bottles of beer on the wall... 3 bottles of beer on the wall... 2 bottles of beer on the wall... 1 bottles of beer on the wall... There are simply no more bottles of beer on the wall. Put a bottle in the recycling, 1 empty bottles in the bin. Put a bottle in the recycling, 2 empty bottles in the bin. Put a bottle in the recycling, 3 empty bottles in the bin. Put a bottle in the recycling, 4 empty bottles in the bin. 

现在,从同一个函数调用中写入从同一列开始的每一行。 你看到瓶子和回收coindice的数量如何? 那是因为两者都使用相同的变量: numberOfBottles

较小的啤酒瓶(及其相应的回收)具有内在function。 您的function树如下所示:

 4 bottles of beer on the wall. 4 bottles of beer. Take one down, pass it around, 3 bottles of beer on the wall. | 3 bottles of beer on the wall. 3 bottles of beer. Take one down, pass it around, 2 bottles of beer on the wall. | | 2 bottles of beer on the wall. 2 bottles of beer. Take one down, pass it around, 1 bottles of beer on the wall. | | | 1 bottles of beer on the wall. 1 bottles of beer. Take one down, pass it around, 0 bottles of beer on the wall. | | | | There are simply no more bottles of beer on the wall. | | | Put a bottle in the recycling, 1 empty bottles in the bin. | | Put a bottle in the recycling, 2 empty bottles in the bin. | Put a bottle in the recycling, 3 empty bottles in the bin. Put a bottle in the recycling, 4 empty bottles in the bin. 

逐步完成这是函数在调试器中执行的操作,您将看到此递归的确切工作方式。 我不是迂腐; 我真的想不出比说这种互动方法更好的方式来说明这是做什么的。

只是简单的图片说明:

在此处输入图像描述

在递归调用返回后运行recycle语句。

每个递归调用最终都会完成,程序将继续执行后面的循环语句,每个语句都有自己的局部变量值。

使用递归,您可以将递归调用之前的所有内容都视为前向循环,并将调用后的所有内容视为后向循环。 (尾递归 – 在函数末尾再次调用函数 – 通常由编译器优化为简单的正向循环。)

这种方式的工作方式是将每个旧函数的参数压入堆栈,并在全部返回时弹出。 请记住,堆栈是后进先出。 因此,从4开始,它按4,然后是3,然后是2,然后是1.当函数返回时,堆栈开始展开,所以你再次以相反的顺序看到参数:1,2,3,4。

它以这种方式工作的原因是,numberOfBottles大于1的singSongFor()每次调用将依次递归调用singSongFor()直到numberOfBottles为0.此时printf("There are simply no more bottles of beer on the wall.\n\n")到达并且该函数将完成,传递给调用函数,该函数将传入1的参数,然后到达printf("Put a bottle in the recycling, %d empty bottles in the bin.\n", numberOfBottles); 并且它本身完成,返回singSongFor(2) ……依此类推,直到你恢复原始数字,在这种情况下为4。