3.1函数定义与调用

50 阅读3分钟

【C语言进阶】函数与递归完全解析:从基础到经典算法

一、函数定义三要素与参数传递

#include <stdio.h>// 【函数声明】(原型)
int add_numbers(int a, int b);
​
int main(void) {
    int x = 5, y = 3;
    int sum = add_numbers(x, y);
    printf("%d + %d = %d\n", x, y, sum);
  
    // 值传递示例
    void try_swap(int a, int b) {
        int temp = a;
        a = b;
        b = temp;  // 【注意】仅修改副本
    }
  
    try_swap(x, y);
    printf("交换后:x=%d, y=%d\n", x, y);  // 值未改变
    return 0;
}
​
// 【函数定义】
int add_numbers(int a, int b) {
    return a + b;
}

【核心要点】:

  • 函数三要素:返回类型、函数名、参数列表
  • C语言采用【值传递】机制(参数副本传递)
  • 函数声明与定义的分离提升代码可读性

二、递归函数深度解析

1. 阶乘递归实现

#include <stdio.h>

long factorial(int n) {
    if (n <= 1) {  // 【终止条件】
        return 1;
    }
    return n * factorial(n - 1);  // 【递归调用】
}

int main(void) {
    printf("5! = %ld\n", factorial(5));  // 输出120
    return 0;
}

2. 汉诺塔问题

void hanoi(int n, char from, char to, char via) {
    if (n == 1) {
        printf("移动圆盘1从 %c 到 %c\n", from, to);
        return;
    }
    hanoi(n-1, from, via, to);     // 移动n-1个到中转柱
    printf("移动圆盘%d从 %c 到 %c\n", n, from, to);
    hanoi(n-1, via, to, from);     // 移动n-1个到目标柱
}

int main(void) {
    hanoi(3, 'A', 'C', 'B');  // 3层汉诺塔
    return 0;
}

【递归要点】:

  • 必须包含明确的终止条件
  • 每次递归应缩小问题规模
  • 注意栈空间限制(一般不超过1000层)

三、函数原型的重要作用

#include <stdio.h>

// 函数原型声明
double calculate_bmi(double weight, double height);

int main(void) {
    double w = 65.0, h = 1.75;
    printf("BMI: %.1f\n", calculate_bmi(w, h));
    return 0;
}

// 实际函数定义
double calculate_bmi(double weight, double height) {
    return weight / (height * height);
}

【原型优势】:

  1. 支持自顶向下的编程风格
  2. 编译器可以进行参数检查
  3. 提升多文件项目的可维护性
  4. 避免隐式函数声明错误

程序员进阶建议

  1. 函数设计原则

    • 单一职责原则:每个函数只做一件事
    • 合理控制函数长度(建议不超过50行)
    • 使用有意义的命名(动词+名词,如calculate_average)
  2. 递归使用指南

    • 优先考虑迭代方案处理简单问题
    • 对于树形结构、分治算法优先使用递归
    • 添加递归深度计数器防止栈溢出
  3. 头文件规范

    • 将函数原型集中放在.h文件
    • 使用#ifndef防止重复包含
    • 添加Doxygen风格注释说明

理解检测

  1. 编写递归函数计算斐波那契数列第n项

  2. 解释以下代码的输出结果:

    void mystery(int x) {
        if(x > 0) {
            printf("%d ", x);
            mystery(x-1);
            printf("%d ", x);
        }
    }
    mystery(3);
    
  3. 重构以下代码使其符合规范:

    // 原始代码
    float avg(int a, int b){
        return (a+b)/2.0f;
    }
    

下期预告:《C语言指针精要:从内存操作到函数指针》,欢迎在评论区提交您的练习题答案或疑问!建议收藏本文反复实践,函数与递归是通往算法世界的必经之路。