递归函数必须设置覆盖所有输入路径的终止条件,否则必然栈溢出崩溃;终止条件需置于函数开头、处理边界与异常情况、返回值要匹配上层逻辑,且须经最小输入验证。

递归函数不设终止条件会直接栈溢出
没有终止条件的递归函数会在调用栈中无限压入新帧,直到耗尽栈空间,程序崩溃并抛出 Segmentation fault(Linux/macOS)或触发 Windows 的栈保护机制。这不是延迟报错,而是必然发生的运行时崩溃。
if 判断必须覆盖所有递归出口路径
终止条件本质是「当前参数下无需再递归」的逻辑判断,它必须写在函数开头,并且要能处理所有可能传入的输入值,尤其是边界和异常情况。
- 对整数参数,常见错误是只写
if (n == 0),却忽略n < 0的情况——比如计算阶乘时传入负数,就会跳过终止条件无限递归 - 对指针/迭代器,不能只检查
ptr == nullptr,还要考虑是否已越界(如链表遍历中ptr->next == nullptr是合法终点,但ptr == nullptr可能是非法起点) - 浮点数递归需格外谨慎,避免用
==判断终止(如if (x == 0.0)),应改用误差范围:if (std::abs(x) < 1e-9)
终止条件的位置和返回值必须与递归逻辑严格匹配
终止条件的返回值不是随便写的,它要能被上一层递归表达式正确接收和组合。例如斐波那契函数:
int fib(int n) {
if (n <= 1) return n; // 终止条件返回 n(即 fib(0)=0, fib(1)=1)
return fib(n-1) + fib(n-2); // 上层依赖这个返回值做加法
}如果这里写成 if (n == 0) return 1;,整个结果就全错了。再比如树的深度计算:
立即学习“C++免费学习笔记(深入)”;
int maxDepth(TreeNode* root) {
if (!root) return 0; // 空节点深度为 0,不是 -1 或 1
return std::max(maxDepth(root->left), maxDepth(root->right)) + 1;
}如果终止时返回 1,会导致空子树也被算作深度 1,结果偏大。
调试时优先检查终止条件是否被真正执行
很多看似“写了终止条件”的 bug,其实是条件永远不满足。可以用打印或断点验证:
- 在终止条件分支里加
std::cout << "base case hit: n=" << n << "\n"; - 观察第一次调用后,是否真进入了该分支;若没进,说明参数没走到你预设的终点,要回头检查递归调用时参数是否在收敛(如每次减 1、除以 2、向 null 移动等)
- 注意无符号类型陷阱:比如
unsigned int n,当执行n-1时,n == 0会回绕成极大值,导致if (n == 0)永远成立,但n-1却不会让它变小
终止条件不是语法占位符,它是递归能否安全落地的唯一锚点。写完一定要用最小可测输入(如 fib(0)、fib(1)、空指针)手动走一遍,确认它真的被触发、返回值合理、且上层能接住。


















