跳到主要内容
🔍

代码示例:1.3.3 函数与递归

全部示例均标注编译命令、适用环境与实测状态;完整验证记录见《03.5-代码编译运行验证记录》。

  • examples/ex1-swap-value-address.c · 传值 vs 传址对照(swap 成功与失败)

    /* ex1-swap-value-address.c —— 传值 vs 传址对照(1.3.3)
     * 适用环境:Linux / Windows(MinGW) 标准:C11
     * 编译:gcc ex1-swap-value-address.c -o ex1 -std=c11 -Wall -Wextra -Wpedantic
     * 运行:./ex1(Windows: ex1.exe)
     */
    #include <stdio.h>
     
    static void swap_by_value(int a, int b)
    {
        int t = a; a = b; b = t;   /* 只交换了形参副本 */
    }
     
    static void swap_by_address(int *a, int *b)
    {
        int t = *a; *a = *b; *b = t;  /* 通过地址间接修改调用者的变量 */
    }
     
    int main(void)
    {
        int x = 10, y = 20;
        swap_by_value(x, y);
        printf("after swap_by_value: x=%d y=%d(未交换)\n", x, y);
        swap_by_address(&x, &y);
        printf("after swap_by_address: x=%d y=%d(已交换)\n", x, y);
        return 0;
    }
     
  • examples/ex2-factorial.c · 阶乘:递归 vs 迭代对照(0..10 全等)

    /* ex2-factorial.c —— 阶乘:递归 vs 迭代对照(1.3.3)
     * 适用环境:Linux / Windows(MinGW) 标准:C11
     * 编译:gcc ex2-factorial.c -o ex2 -std=c11 -Wall -Wextra -Wpedantic
     * 运行:./ex2(Windows: ex2.exe)
     */
    #include <stdio.h>
     
    static long long factorial_rec(int n)
    {
        if (n <= 1) return 1;            /* 基准情形 */
        return (long long)n * factorial_rec(n - 1);  /* 递归步骤:规模递减 */
    }
     
    static long long factorial_iter(int n)
    {
        long long r = 1;
        for (int i = 2; i <= n; i++) r *= i;
        return r;
    }
     
    int main(void)
    {
        for (int n = 0; n <= 10; n++) {
            printf("factorial(%2d): rec=%10lld iter=%10lld\n", n, factorial_rec(n), factorial_iter(n));
        }
        return 0;
    }
     
  • examples/ex3-hanoi.c · 汉诺塔(3 盘,7 步;2^n - 1 验证)

    /* ex3-hanoi.c —— 汉诺塔(3 盘,1.3.3)
     * 适用环境:Linux / Windows(MinGW) 标准:C11
     * 编译:gcc ex3-hanoi.c -o ex3 -std=c11 -Wall -Wextra -Wpedantic
     * 运行:./ex3(Windows: ex3.exe)
     */
    #include <stdio.h>
     
    static int move_count = 0;
     
    static void hanoi(int n, char from, char via, char to)
    {
        if (n == 1) {                      /* 基准情形 */
            printf("move disk 1: %c -> %c\n", from, to);
            move_count++;
            return;
        }
        hanoi(n - 1, from, to, via);       /* 递归步骤 */
        printf("move disk %d: %c -> %c\n", n, from, to);
        move_count++;
        hanoi(n - 1, via, from, to);
    }
     
    int main(void)
    {
        hanoi(3, 'A', 'B', 'C');
        printf("total moves = %d(2^3 - 1 = 7)\n", move_count);
        return 0;
    }
     
  • examples/ex4-infinite-recursion.txt · 无限递归与栈溢出(conceptual:静态讲解,不运行)

    # 1.3.3 无限递归与栈溢出(conceptual 讲解,不编译不运行)
    # 本文件是"概念讲解型"示例(example_kind=conceptual):只讲机制,不运行无限递归。
    #
    # 危险写法(只讲解,绝不执行):
    #   static void bad(int n) { bad(n); }   /* 无基准情形、参数不递减 */
    #
    # 为什么必然栈溢出?
    # 1. 每次函数调用都在调用栈上分配一个栈帧(局部变量、返回地址、保存的寄存器等);
    # 2. 递归三要素缺一(无基准情形/参数不递减)时,调用永不返回,栈帧只增不减;
    # 3. 栈空间有限(Linux 默认 8MB;嵌入式任务栈通常仅 1-16KB),耗尽即 stack overflow,
    #    常见表现为段错误(SIGSEGV)或栈保护(stack smashing)崩溃。
    #
    # 正确写法(三要素齐全):
    #   static long long factorial_rec(int n) {
    #       if (n <= 1) return 1;              /* ① 基准情形 */
    #       return (long long)n * factorial_rec(n - 1);  /* ② 递归步骤 ③ n-1 规模递减 */
    #   }
    #
    # 工程建议:
    # - 递归前先估算最大深度 × 每层栈帧大小,确认远小于可用栈;
    # - 嵌入式(栈小)或深度不可预估时改迭代(ex2 的 iter 版);
    # - 不依赖编译器尾调用优化(优化行为,标准不保证)。
    #
    # 一句可背的结论:递归三要素缺一不可;栈溢出不是"报错"而是资源耗尽,防患于设计。