【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);
}
【原型优势】:
- 支持自顶向下的编程风格
- 编译器可以进行参数检查
- 提升多文件项目的可维护性
- 避免隐式函数声明错误
程序员进阶建议
-
函数设计原则
- 单一职责原则:每个函数只做一件事
- 合理控制函数长度(建议不超过50行)
- 使用有意义的命名(动词+名词,如calculate_average)
-
递归使用指南
- 优先考虑迭代方案处理简单问题
- 对于树形结构、分治算法优先使用递归
- 添加递归深度计数器防止栈溢出
-
头文件规范
- 将函数原型集中放在.h文件
- 使用#ifndef防止重复包含
- 添加Doxygen风格注释说明
理解检测
-
编写递归函数计算斐波那契数列第n项
-
解释以下代码的输出结果:
void mystery(int x) { if(x > 0) { printf("%d ", x); mystery(x-1); printf("%d ", x); } } mystery(3);
-
重构以下代码使其符合规范:
// 原始代码 float avg(int a, int b){ return (a+b)/2.0f; }
下期预告:《C语言指针精要:从内存操作到函数指针》,欢迎在评论区提交您的练习题答案或疑问!建议收藏本文反复实践,函数与递归是通往算法世界的必经之路。