18 · 递归与可变参数
递归:函数调用自己
int factorial(int n) {
if (n <= 1) return 1; // ✅ 必须有终止条件!
return n * factorial(n - 1);
}
- 两个必要条件:终止条件 + 向终止条件收敛。
- 每次调用在栈上压一帧,递归太深 → 栈溢出(Stack Overflow)。
- 斐波那契那种会重复计算,效率差,可用记忆化或改循环。
// 经典:汉诺塔
void hanoi(int n, char a, char b, char c) {
if (n == 1) { printf("%c -> %c\n", a, c); return; }
hanoi(n - 1, a, c, b);
printf("%c -> %c\n", a, c);
hanoi(n - 1, b, a, c);
}
可变参数(... + <stdarg.h>)
#include <stdarg.h>
int sum(int count, ...) {
va_list ap;
va_start(ap, count); // 从 count 之后开始取
int s = 0;
for (int i = 0; i < count; i++)
s += va_arg(ap, int); // 按 int 类型取出
va_end(ap); // 必须收尾
return s;
}
sum(3, 10, 20, 30); // → 60
- 你天天用的
printf(fmt, ...)就是可变参数。 - 必须手动知道参数个数和类型(靠第一个参数或格式串),C 不会帮你检查。
⚡ Java 对比
Java 可变参数 int... nums 有数组和长度,安全;C 的 ... 完全靠约定,取错类型 = 未定义行为。