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

递归函数不设终止条件会直接栈溢出
没有终止条件的递归函数会在调用栈中无限压入新帧,直到耗尽栈空间,程序崩溃并抛出 Segmentation fault(Linux/macOS)或触发 Windows 的栈保护机制。这不是延迟报错,而是必然发生的运行时崩溃。
if 判断必须覆盖所有递归出口路径
终止条件本质是「当前参数下无需再递归」的逻辑判断,它必须写在函数开头,并且要能处理所有可能传入的输入值,尤其是边界和异常情况。
- 对整数参数,常见错误是只写
if (n == 0),却忽略n 的情况——比如计算阶乘时传入负数,就会跳过终止条件无限递归 - 对指针/迭代器,不能只检查
ptr == nullptr,还要考虑是否已越界(如链表遍历中ptr->next == nullptr是合法终点,但ptr == nullptr可能是非法起点) - 浮点数递归需格外谨慎,避免用
==判断终止(如if (x == 0.0)),应改用误差范围:if (std::abs(x)
终止条件的位置和返回值必须与递归逻辑严格匹配
终止条件的返回值不是随便写的,它要能被上一层递归表达式正确接收和组合。例如斐波那契函数:
int fib(int n) {
if (n <p>如果这里写成 <code>if (n == 0) return 1;</code>,整个结果就全错了。再比如树的深度计算:</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/gongju/2823" title="C++14"><img
src="https://img.php.cn/upload/manual/001/431/639/6ac8b33c327c4749.png" alt="C++14" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="overflowclass">C++14</a>
<p class="overflowclass">C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。</p>
</div>
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div><pre class="brush:php;toolbar:false;">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 - 观察第一次调用后,是否真进入了该分支;若没进,说明参数没走到你预设的终点,要回头检查递归调用时参数是否在收敛(如每次减 1、除以 2、向 null 移动等)
- 注意无符号类型陷阱:比如
unsigned int n,当执行n-1时,n == 0会回绕成极大值,导致if (n == 0)永远成立,但n-1却不会让它变小
终止条件不是语法占位符,它是递归能否安全落地的唯一锚点。写完一定要用最小可测输入(如 fib(0)、fib(1)、空指针)手动走一遍,确认它真的被触发、返回值合理、且上层能接住。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










