030 函数的递归调用

/********************030 函数的递归调用************************
 * 将一个整数你转换成为字符串。   
 * C语言精彩编程百例 第30*/
#include<stdio.h>

void convert(int n)
{
    int i;
    i=n/10;
    if(i!=0)
        convert(i);
    putchar(n%10+'0');
}

void main()
{
    int number;
    printf("输入整数:");
    scanf("%d",&number);
    printf("输出是:");
    if(number<0)
    {
        putchar('-');
        number=-number;
    }
    convert(number);
    putchar('\n');
}

编译器汇编的结果:

    .file   "030.c"
    .text
    .align 2
.globl _convert
    .def    _convert;   .scl    2;  .type   32; .endef
_convert:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $8, %esp
    movl    8(%ebp), %ecx       # ecx=n 
    movl    $1717986919, %eax  # eax=1717986919
    imull   %ecx            # edx:eax=n*1717986919
    sarl    $2, %edx       # edx=n*1717986919/2^34=n*0.1
    movl    %ecx, %eax      # eax=n
    sarl    $31, %eax      # 右移31位,取n的符号
    subl    %eax, %edx      # edx = n*0.1 - n的符号, 向零取整结果
    movl    %edx, %eax      # eax = n*0.1
    movl    %eax, -4(%ebp)      # i=n/10
    cmpl    $0, -4(%ebp)       # if(i!=0)
    je  L4
    subl    $12, %esp      # 调用 _convert
    pushl   -4(%ebp)
    call    _convert
    addl    $16, %esp
L4:
    subl    $12, %esp      # 准备 printf
    movl    8(%ebp), %ecx       # ecx=n
    movl    $1717986919, %eax  # eax=1717986919
    imull   %ecx            # edx:eax=n*1717986919
    sarl    $2, %edx       # edx=n*1717986919/2^34=n*0.1
    movl    %ecx, %eax      # eax=n
    sarl    $31, %eax      # 右移31位,取n的符号
    subl    %eax, %edx      # edx = n*0.1 - n的符号, 向零取整结果
    movl    %edx, %eax      # edx = n/10 
    sall    $2, %eax       # eax=n*0.1*4
    addl    %edx, %eax              # eax=n*0.1*5
    addl    %eax, %eax      # eax=n*0.1*10
    subl    %eax, %ecx      # ecx=n-n*0.1*10
    movl    %ecx, %eax      # eax=n%10 // 编译器为mod做的优化 ... 
    addl    $48, %eax      # n%10+'0'
    pushl   %eax
    call    _putchar
    addl    $16, %esp
    leave
    ret
    .def    ___main;    .scl    2;  .type   32; .endef
LC0:
    .ascii "\312\344\310\353\325\373\312\375\243\272\0"
LC1:
    .ascii "%d\0"
LC2:
    .ascii "\312\344\263\366\312\307\243\272\0"
    .align 2
.globl _main
    .def    _main;  .scl    2;  .type   32; .endef
_main:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $8, %esp
    andl    $-16, %esp
    movl    $0, %eax
    movl    %eax, -8(%ebp)
    movl    -8(%ebp), %eax
    call    __alloca
    call    ___main
    subl    $12, %esp
    pushl   $LC0
    call    _printf
    addl    $16, %esp
    subl    $8, %esp
    leal    -4(%ebp), %eax
    pushl   %eax
    pushl   $LC1
    call    _scanf
    addl    $16, %esp
    subl    $12, %esp
    pushl   $LC2
    call    _printf
    addl    $16, %esp
    cmpl    $0, -4(%ebp)
    jns L6
    subl    $12, %esp
    pushl   $45
    call    _putchar
    addl    $16, %esp
    leal    -4(%ebp), %eax
    negl    (%eax)
L6:
    subl    $12, %esp
    pushl   -4(%ebp)
    call    _convert
    addl    $16, %esp
    subl    $12, %esp
    pushl   $10
    call    _putchar
    addl    $16, %esp
    leave
    ret
    .def    _scanf; .scl    2;  .type   32; .endef
    .def    _printf;    .scl    2;  .type   32; .endef
    .def    _putchar;   .scl    2;  .type   32; .endef
函数递归调用函数嵌套调用种特殊形式,在调用函数的过程中又直接或者间接地调用函数本身,称之为函数递归调用递归调用必须有两个明确的阶段:回溯和递推。回溯是次次递归调用下去,是个重复的过程,但每次重复问题的规模都应该有所减少,直到逼近个最终的结果,即回溯阶段定要有个明确的结束条件;递推是往回层推算出结果[^1]。 递归方法是从结果出发,归纳出后结果与前结果直到初值为止存在的关系,要求通过分析得到:初值 + 递归函数,然后设计函数,这个函数不断使用下级值调用自身,直到结果已知处。设计递归函数般选择控制结构[^2]。 以下是不同语言函数递归调用的示例: ### Python 示例 ```python import sys sys.setrecursionlimit(2048) def foo(n): print('from foo', n) foo(n + 1) # 调用示例 # foo(0) def age(n): if n == 1: return 18 return age(n - 1) + 2 # 调用 age 函数 print(age(5)) ``` 在上述 Python 代码中,`foo` 函数直接调用自身,但没有明确的结束条件,会导致无限递归。`age` 函数则是个正确的递归示例,当 `n` 等于 1 时返回 18,否则返回 `age(n - 1) + 2`,通过不断递归调用自身,最终计算出 `age(5)` 的值[^1]。 ### C 语言示例 ```c #include <stdio.h> // 递归法 int Age(int n) { int x; if (n == 1) { // 是递归停止的条件,当 n = 1 时停止递归调用 x = 10; } else { x = Age(n - 1) + 2; // 调用自身的 Age 函数 } return x; } int main() { printf("%d\n", Age(5)); return 0; } ``` 在这个 C 语言示例中,`Age` 函数通过递归调用自身来计算年龄。当 `n` 等于 1 时,返回 10,否则返回 `Age(n - 1) + 2`,在 `main` 函数调用 `Age(5)` 并输出结果[^3]。 ### Java 示例 ```java public class RecursionExample { public static void printStar(int n, int m) { if (n > 10000) { return; } for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { System.out.print("*\t"); } System.out.println(); } } public static int factorial(int n) { if (n == 0 || n == 1) { return 1; } return n * factorial(n - 1); } public static void main(String[] args) { // 调用 printStar 函数 printStar(3, 3); // 调用 factorial 函数 System.out.println(factorial(5)); } } ``` 在 Java 示例中,`printStar` 函数虽然有边界条件但不是典型的递归函数,`factorial` 函数递归计算阶乘的函数,当 `n` 等于 0 或 1 时返回 1,否则返回 `n * factorial(n - 1)`,在 `main` 函数调用 `factorial(5)` 计算 5 的阶乘[^5]。 ### 递归调用的终止条件 递归调用必须有明确的终止条件,否则会导致无限递归,最终使程序崩溃。例如在 `age` 函数和 `Age` 函数中,当 `n` 等于 1 时就是递归的终止条件,在 `factorial` 函数中,当 `n` 等于 0 或 1 时是递归的终止条件[^1][^3]。 ### 递归调用的执行过程 以 `factorial` 函数为例,调用 `factorial(5)` 后即进入函数体,由于 `n` 不等于 0 或 1,所以会调用 `factorial(4)`,以此类推,直到 `n` 等于 1 时递归终止,然后逐层返回结果,最终计算出 `factorial(5)` 的值[^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值