递归与可变参数
概念说明
递归是函数在定义中直接或间接调用自己。 它适合描述具有相同子结构的问题,但必须有明确的结束条件,否则会无限调用下去。
递归的表达能力很强,但代价也很真实。 每多递归一层,就会多一层函数调用开销和栈空间消耗,所以它并不适合所有问题。
可变参数函数允许参数个数不固定,常见于 printf 这类接口。
在 C 里,这类函数通常要借助 stdarg.h 提供的 va_list、va_start、va_arg 和 va_end。
语法/规则
- 递归函数至少需要“递归推进”和“终止条件”两个部分。
- 如果递归深度较大,要考虑栈空间和重复计算带来的成本。
- 可变参数函数通常至少需要一个固定参数,用来描述后续参数的个数或格式。
va_arg读取参数时必须使用正确类型,否则结果不可预期。- 传入可变参数时要注意默认参数提升,例如
char、short会提升为int。 - 处理完可变参数后要调用
va_end完成收尾。 - 如果一个问题能用简单循环表达,就不必为了“高级感”强行使用递归。
示例
| |
输出结果:
| |
常见错误
- 递归函数没有正确结束条件,导致栈不断增长直到程序崩溃。
- 把本可复用的递归结果反复重复计算,导致时间开销急剧上升。
va_arg读取的类型和实际传入类型不一致,造成未定义行为。- 写了可变参数函数却没有额外信息来判断参数个数,导致读取边界不清楚。
- 忘记调用
va_end,或者在读取完成后继续使用已经失效的va_list。