【问题标题】:Understanding recursion in C理解 C 中的递归
【发布时间】:2012-08-02 09:13:32
【问题描述】:

这是一个递归程序。但我不明白在这个节目中发生的事件顺序

#include<stdio.h>
count(int);
main() 
{
    int x=5;
    count(x);
}
count(int y)
{
    if(y>0)
    {
        count(--y);
        printf("%d ",y);
    }
}

输出是:

4 3 2 1 0 ...

但我不明白第一次调用 count(5) 和调用 count(4) 时会发生什么。控件是否立即转到函数的开头?还是首先打印y 的值,然后再次转到函数count() 的开头?

【问题讨论】:

  • 尝试使用调试器(在Linux上意味着gdb在使用gcc -Wall -g编译后),逐步运行程序或至少在count中设置断点
  • 你问的是程序是如何执行的?一步一步来??
  • @chris 程序不使用void main;它使用假定返回 int,这是 pre-ISO (K&R) C。
  • 是的,我想学习控制序列
  • @ecatmur,我发帖的时候是void。

标签: c function recursion


【解决方案1】:

就像一堆盘子。

 1       2         3         4          5
                                      count(0)
                            count(1)  count(1)
                  count(2)  count(2)  count(2)
        count(3)  count(3)  count(3)  count(3)
main    main      main      main      main


count(0) prints nothing

转到第 4 步

count(1) prints 1

转到第 3 步

count(2) prints 2 ...

所以要获得4 3 2 1 的输出,您需要交换count(--y) 和printf("%d",y) 行。

【讨论】:

  • 如果我换行我也会得到 5 个
  • 如果换行,printf 将被调用之前 --y。所以y在打印出来的时候还是有5的值。
  • 我只想知道函数count(--y) 何时被调用...控制权是传递到函数的开头还是打印y 的值??
  • @AmolSingh 它将转到函数的开头
  • @AmolSingh 当函数被调用时,函数中的代码会被执行……你为什么或者怎么能期待别的?
【解决方案2】:

您可以轻松地单步执行代码以查看其中发生了什么,使用稍微编辑的代码:

#include<stdio.h>

void count(int);

int main() 
{
    int x=5;
    count(x);
}
void count(int y)
{
    if(y>0)
    {
        count(--y);
        printf("%d ",y);
    }
}

现在看看执行期间会发生什么。查看 gdb 会话:

(gdb) b count
Breakpoint 2 at 0x4004ea: file rc.c, line 10.
(gdb) c
Continuing.

Breakpoint 2, count (y=5) at rc.c:10
(gdb) c
Continuing.

Breakpoint 2, count (y=4) at rc.c:10
(gdb) c
Continuing.

Breakpoint 2, count (y=3) at rc.c:10
(gdb) c
Continuing.

Breakpoint 2, count (y=2) at rc.c:10
(gdb) c
Continuing.

Breakpoint 2, count (y=1) at rc.c:10
(gdb) c
Continuing.

Breakpoint 2, count (y=0) at rc.c:10
(gdb) bt
#0  count (y=0) at rc.c:10
#1  0x00000000004004fe in count (y=0) at rc.c:12
#2  0x00000000004004fe in count (y=1) at rc.c:12
#3  0x00000000004004fe in count (y=2) at rc.c:12
#4  0x00000000004004fe in count (y=3) at rc.c:12
#5  0x00000000004004fe in count (y=4) at rc.c:12
#6  0x00000000004004dd in main () at rc.c:6
(gdb) 

后面的痕迹讲述了整个历史。看到每个对 count 的调用都是“堆叠的”。但没有人回来。还没有打印任何东西。

现在看看他们是如何返回的:

(gdb) n
count (y=0) at rc.c:13 /* count(y = 0) returned first , it will not cause any printing*/
(gdb) n
(gdb) n
count (y=1) at rc.c:13 /* count(y = 1) returned second, this will cause printing 0 */
(gdb) n
(gdb) n
count (y=2) at rc.c:13 /* subsequent returns will cause printing of 1,2,3 etc */
(gdb) n
(gdb) n
count (y=3) at rc.c:13
(gdb) n
(gdb) n
count (y=4) at rc.c:13
(gdb) c
Continuing.
0 1 2 3 4 

【讨论】:

  • 假设我在count(--y) 之后有一个printf("wdf"); 声明。那么会发生什么?
  • 你会得到一个“wdf”的重复打印。
  • 当count(y = 0) 将返回到它被调用的地方。它由 count(y = 1) 调用。因此它将在调用序列之后返回到指令,并执行那里的任何内容。在这种情况下,它是一个打印语句。
【解决方案3】:

这就像一个算术级数。 从 N > 0 开始,每次减一,直到达到 0。 更多关于递归的信息(使用阶乘示例,你就会明白): http://en.wikipedia.org/wiki/Recursion

希望对您有所帮助。

问候。

【讨论】:

    【解决方案4】:
    void count(int y)
    {
        if(y>0)
        {
            printf("%d ",--y);
            count(y);
        }
    }
    

    打印 y-1, y-2, ... 0。

    如果y &lt;= 0,则无事可做。如果y &gt; 0,它递减y打印递减后的y,然后调用count用递减值y打印剩余的值。

    另一个例子,这个:

    void count(int y)
    {
        if(y>0)
        {
            printf("%d ",--y);
            count(y);
            printf("amol");
        }
    }
    

    打印 y-1, y-2, ... 0 amol...amol (y 次)。

    它通过打印 y-1 来实现,然后递归调用 count(y-1) 打印 y-2, ..0, amol(y-1 次),然后打印剩余的“amol”。

    【讨论】:

    • 假设在count(y) 之后我们有printf("amol") 那么输出将如何以及为什么
    • @AmolSingh - 你怎么看?
    • @AmolSingh - 不,编译并运行程序,然后尝试理解它。
    • 我看不出这是对这个问题的回答。
    • 你是对的,输出是 4 3 2 1 0 amolamolamolamol,但是 printf("amol") 的声明是如何执行的 ..?
    【解决方案5】:

    可以通过将事物替换为等效项来转换程序:变量及其值,函数调用与函数代码,常数条件与选定代码。例如,

    main() 
    {
        int x=5;
        count(x);
    }
    

    -->

    main() 
    {
        count(5);
    }
    

    -->

    main() 
    {
        if(5>0)
        {
            count(4);
            printf("%d ",4);
        }
    }
    

    -->

    main() 
    {
        count(4);
        printf("%d ",4);
    }
    

    -->

    main() 
    {
        if(4>0)
        {
            count(3);
            printf("%d ",3);
        }
        printf("%d ",4);
    }
    

    -->

    main() 
    {
        count(3);
        printf("%d ",3);
        printf("%d ",4);
    }
    

    --> ...-->

    main() 
    {
        count(0);
        printf("%d ",0);
        printf("%d ",1);
        printf("%d ",2);
        printf("%d ",3);
        printf("%d ",4);
    }
    

    -->

    main() 
    {
        if(0>0)
        {
            count(-1);
            printf("%d ",-1);
        }
        printf("%d ",0);
        printf("%d ",1);
        printf("%d ",2);
        printf("%d ",3);
        printf("%d ",4);
    }
    

    -->

    main() 
    {
        printf("%d ",0);
        printf("%d ",1);
        printf("%d ",2);
        printf("%d ",3);
        printf("%d ",4);
    }
    

    【讨论】:

    • 这很好,但是如果printf 在if 块之后呢?
    • @AmolSingh 请停止拖钓。
    猜你喜欢
    • 2021-12-14
    • 2012-07-26
    • 2014-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多