C语言中的递归是如何工作的?

发布于 2024-10-29 12:20:27 字数 300 浏览 1 评论 0原文

我试图了解递归在 C 中是如何工作的。任何人都可以给我解释控制流吗?

#include <stdio.h>
/* printd: print n in decimal */
void printd(int n)
{
  if (n < 0)
  {
    putchar('-');
    n = -n;
  }
  if (n / 10) printd(n / 10);
  putchar(n % 10 + '0');
}

int main()
{
  printd(123);
  return 0;
}

I'm trying to understand how recursion works in C. Can anyone give me an explanation of the control flow?

#include <stdio.h>
/* printd: print n in decimal */
void printd(int n)
{
  if (n < 0)
  {
    putchar('-');
    n = -n;
  }
  if (n / 10) printd(n / 10);
  putchar(n % 10 + '0');
}

int main()
{
  printd(123);
  return 0;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

傲性难收 2024-11-05 12:20:27

控制流程如下所示(其中 -> 是函数调用)

main()
 └─> printd(123)
      ├─> printd(12)
      │    ├─> printd(1)
      │    │    └─> putchar('1')
      │    └─> putchar('2')
      └─> putchar('3')

The control flow looks like this (where -> is a function call)

main()
 └─> printd(123)
      ├─> printd(12)
      │    ├─> printd(1)
      │    │    └─> putchar('1')
      │    └─> putchar('2')
      └─> putchar('3')
真心难拥有 2024-11-05 12:20:27
Call printd(123)
    (123 / 10) != 0, so Call printd(12)
        (12 / 10) != 0, so Call printd(1)
            (1 / 10) == 0, so Call putchar "1"
        Call putchar "2"
    Call putchar "3"
return 0 (from main())
Call printd(123)
    (123 / 10) != 0, so Call printd(12)
        (12 / 10) != 0, so Call printd(1)
            (1 / 10) == 0, so Call putchar "1"
        Call putchar "2"
    Call putchar "3"
return 0 (from main())
不喜欢何必死缠烂打 2024-11-05 12:20:27

要了解递归,您需要了解存储模型。尽管有多种变体,但基本上是“自动”存储,用于包含自动变量、参数、编译器临时值和调用/返回信息的存储被安排为“堆栈”。这是一种存储结构,从进程存储中的某个位置开始,并随着过程的调用而“向上”(增加地址)或“向下”(减少地址)“增长”。

可以从几个变量开始:

00 -- Variable A -- 27
01 -- Variable B -- 45

然后我们决定调用过程 X,因此我们生成一个 A+B 参数:

02 -- Parameter -- 72

我们需要保存希望控制返回的位置。假设指令 104 是调用,那么我们将 105 作为返回地址:

03 -- Return address -- 105

我们还需要保存上述“堆栈帧”的大小——四个字,其中 5 个字是帧大小本身:

04 -- Frame size -- 5

现在我们开始在 X 中执行。它需要一个变量C:

05 -- Variable C -- 123

并且需要引用该参数。但它是如何做到这一点的呢?嗯,在入口处,堆栈指针被设置为指向 X 的“堆栈帧”的“底部”。我们可以将“底部”设为多个位置中的任何一个,但让我们将其设为 X 框架中的第一个变量。

05 -- Variable C -- 123  <=== (Stack frame pointer = 5)

但我们仍然需要引用该参数。我们知道,我们的帧“下方”(堆栈帧指针指向的位置)是(按地址递减顺序)帧大小、返回地址,然后是我们的参数。因此,如果我们从 5 中减去 3(对于这 3 个值),我们会得到 2,这是参数的位置。

请注意,此时我们并不真正关心帧指针是 5 还是 55555——我们只是减去引用参数,添加引用我们的局部变量。如果我们想要进行调用,我们将“堆栈”参数、返回地址和帧大小,就像我们在第一次调用时所做的那样。我们可以一次又一次地进行调用,然后继续“推送”堆栈帧。

要返回 we,请将帧大小和返回地址加载到寄存器中。从堆栈帧指针中减去帧大小并将返回地址放入指令计数器中,然后我们回到调用过程。

现在这过于简单化了,有许多不同的方法来处理堆栈帧指针、参数传递和跟踪帧大小。但无论如何,基础知识都适用。

To understand recursion, you need to understand the storage model. Though there are several variations, basically "automatic" storage, the storage used to contain automatic variables, parameters, compiler temps, and call/return information, is arranged as a "stack". This is a storage structure starting at some location in process storage and "growing" either "up" (increasing addresses) or "down" (decreasing addresses) as procedures are called.

One might start out with a couple of variables:

00 -- Variable A -- 27
01 -- Variable B -- 45

Then we decide to call procedure X, so we generate a parameter of A+B:

02 -- Parameter -- 72

We need to save the location where we want control to return. Say instruction 104 is the call, so we'll make 105 the return address:

03 -- Return address -- 105

We also need to save the size of the above "stack frame" -- four words, 5 with the frame size itself:

04 -- Frame size -- 5

Now we begin executing in X. It needs a variable C:

05 -- Variable C -- 123

And it needs to reference the parameter. But how does it do that? Well, on entry a stack pointer was set to point at the "bottom" of X's "stack frame". We could make the "bottom" be any of several places, but let's make it the first variable in X's frame.

05 -- Variable C -- 123  <=== (Stack frame pointer = 5)

But we still need to reference the parameter. We know that "below" our frame (where the stack frame pointer is pointing) are (in decreasing address order) the frame size, return address, and then our parameter. So if we subtract 3 (for those 3 values) from 5 we get 2, which is the location of the parameter.

Note that at this point we don't really care if our frame pointer is 5 or 55555 -- we just subtract to reference parameters, add to reference our local variables. If we want to make a call we "stack" parameters, return address, and frame size, as we did with the first call. We could make call after call after call and just continue "pushing" stack frames.

To return we, load the frame size and the return address into registers. Subtract frame size from the stack frame pointer and put the return address into the instruction counter and we're back in the calling procedure.

Now this is an over-simplification, and there are numerous different ways to handle the stack frame pointer, parameter passing, and keeping track of frame size. But the basics apply regardless.

一影成城 2024-11-05 12:20:27

通过将问题分解为 2 个较小的问题,可以在 C(或任何其他编程语言)中实现递归。

你的例子: 打印一个数字可以分为这两个部分

  1. 打印第一部分(如果存在
  2. )打印最后一个数字

要打印“123”,更简单的问题是打印“12”(12123 / 10) 并打印“3”。
要打印“12”,更简单的问题是打印“1”(112 / 10)和打印“2”。
要打印“1”,...只需打印“1”。

You have recursion in C (or any other programming language) by breaking a problem into 2 smaller problems.

Your example: print a number can be broken in these 2 parts

  1. print the first part if it exists
  2. print the last digit

To print "123", the simpler problems are then to print "12" (12 is 123 / 10) and to print "3".
To print "12", the simpler problems are then to print "1" (1 is 12 / 10) and to print "2".
To print "1", ... just print "1".

安静 2024-11-05 12:20:27
#include <stdio.h>

#define putd(d) (printf("%d", d))

#define RECURSIVE

void rprint(int n)
{
#ifndef RECURSIVE
    int i = n < 0 ? -n : n;

    for (; i / 10; i /= 10)
        putd(i % 10);

    putd(i % 10);

    if (n < 0)
        putchar('-');
    /* Don't forget to reverse :D */
#else
    if (n < 0) {
         n = -n;
         putchar('-');
    }

    int i = n / 10;
    if (i)
        rprint(i);

    putd(n % 10);
#endif
}

int main()
{
    rprint(-321);
    return 0;
}
#include <stdio.h>

#define putd(d) (printf("%d", d))

#define RECURSIVE

void rprint(int n)
{
#ifndef RECURSIVE
    int i = n < 0 ? -n : n;

    for (; i / 10; i /= 10)
        putd(i % 10);

    putd(i % 10);

    if (n < 0)
        putchar('-');
    /* Don't forget to reverse :D */
#else
    if (n < 0) {
         n = -n;
         putchar('-');
    }

    int i = n / 10;
    if (i)
        rprint(i);

    putd(n % 10);
#endif
}

int main()
{
    rprint(-321);
    return 0;
}
恬淡成诗 2024-11-05 12:20:27

递归在堆栈上工作,即先进后出。

递归是一个使用不同参数调用自身直到达到基本条件的过程。当执行过多的递归调用时,就会发生堆栈溢出。

Recursion works on stack i.e, first in last out.

Recursion is a process of calling itself with different parameters until a base condition is achieved. Stack overflow occurs when too many recursive calls are performed.

听风念你 2024-11-05 12:20:27

代码:

main()
{print f ("stat");
main();
print f ("end")  ;
}

代码:

main()
{int n, res;
pf("enter n value");
sf("%d",&n);

=fact(n);
}
int fact(int n)
{int res;
if(n==0)
{
res=1;
}
else
{
res = n*fact (n-1);
}
return res;
}

Code:

main()
{print f ("stat");
main();
print f ("end")  ;
}

Code:

main()
{int n, res;
pf("enter n value");
sf("%d",&n);

=fact(n);
}
int fact(int n)
{int res;
if(n==0)
{
res=1;
}
else
{
res = n*fact (n-1);
}
return res;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文