这段代码如何跳转到最后一个字符串并反转堆栈?

时间:2014-02-03 20:51:50

标签: c stack

我正在学习C,这是一个自学成才的东西。这很好,但是当我有问题时会变得毛茸茸,所以我希望得到一些帮助!

我有一些代码,我被指示编写,我理解代码,我理解堆栈如何工作(取一个,进入另一堆等),main()将始终运行。

但我不明白为什么,在numberOfBottles达到0后,它不会继续循环。为什么它会反转堆栈,首先,它是如何跳转到最后一个字符串的?

#include <stdio.h>

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);
        printf("Put a bottle in the recycling, %d empty bottles in the bin. \n", numberOfBottles);
    }
}
int main(int argc, const char * argv[])
{
    singSongFor(4);
    return 0;
}

所以在if/else的底部,我们“在回收中放了一个瓶子”,但我正在读它的方式是:

4 take one down
3 take one down 
2 take one down 
1 take one down
0 "there are simply no more bottles..."

现在它已经达到0,我认为它应该循环说...      “根本就没有瓶子......” 或者,至少,当它在堆叠中添加另一个瓶子时,为什么不说“哦,我又喝了一瓶。拿下一瓶?”

是什么原因导致代码转到另一个已建立的堆栈并从1-4跳过“放一个瓶子......”而不再遍历整个if/else

2 个答案:

答案 0 :(得分:5)

这是一个recursive function,这意味着它“循环”,因为它自称。当函数以4的参数运行时,它再次使用参数3调用自身。当它变为零时,由于if语句,它不再调用自身,因此“循环”终止,控制开始返回函数调用链。

  

是什么原因导致代码转到另一个已建立的堆栈并从1-4跳过“放一个瓶子......”并且不再遍历整个if / else?

没有“其他堆叠”。我认为通过这种方式思考堆栈会让你感到困惑。只需将其视为一个不断调用自身直到其参数为零的函数。如果你要绘制这个程序的嵌套函数调用序列,它看起来像这样(注意这是一个调用堆栈图,而不是C代码):

main()
{
    singSongFor(4)
    {
        // prints "4 take one down"
        singSongFor(3)
        {
            // prints "3 take one down"
            singSongFor(2)
            {
                // prints "2 take one down"
                singSongFor(1)
                {
                    // prints "1 take one down"
                    singSongFor(0)
                    {
                        // prints "0 there are simply..."
                    }
                    // prints "recycling 1"
                }
                // prints "recycling 2"
            }
            // prints "recycling 3"
        }
        // prints "recycling 4"
    }
    // end
}

答案 1 :(得分:1)

在进行回收中的Put瓶印刷之前,你一直打电话给singSongFor。它最终将击中瓶子== 0然后它将不再递归循环,因为它无法达到singSongFor呼叫并完全结束。作为一个c#人我建议将其写为for循环,以便能够更好地可视化它,你可能会在递归中看到错误。快乐的编码。