阶乘递归易致栈溢出和整数溢出,int仅支持到12!,unsigned long long最多到20!;循环实现更安全可控,需校验乘法是否越界并返回错误码。

用 int 递归写阶乘会很快溢出
递归实现看起来简洁,但实际使用中必须警惕整数溢出和栈溢出。C++ 标准不保证尾递归优化,factorial(10000) 这种调用大概率触发 stack overflow。更现实的问题是:int 在大多数平台下最大值约 21 亿,factorial(13) 就已超限(13! = 6227020800)。若真需要大数阶乘,得换容器或库,比如 unsigned long long 最多撑到 factorial(20)。
循环实现更安全、更可控
循环避免了函数调用开销和栈风险,也方便做边界检查和提前退出。关键点在于初始值设为 1,且循环从 2 开始(1! 和 0! 都是 1)。
long long factorial(int n) {
if (n < 0) return -1; // 无效输入
long long result = 1;
for (int i = 2; i <= n; ++i) {
if (result > LLONG_MAX / i) return -1; // 溢出预检
result *= i;
}
return result;
}-
n == 0或n == 1时,for循环不执行,直接返回1 - 溢出检查用
LLONG_MAX / i而不是result * i > LLONG_MAX,防止乘法本身已越界 - 返回
-1表示错误,调用方需判断,不能默认结果一定有效
递归版本只适合教学或小范围验证
如果坚持用递归,至少要加输入校验,并明确限定安全范围(比如 n )。否则看似优雅,实则隐藏运行时崩溃风险。
long long factorial_recursive(int n) {
if (n < 0) return -1;
if (n > 20) return -1; // 明确拒绝高风险输入
if (n <= 1) return 1;
return n * factorial_recursive(n - 1);
}- 没有尾递归优化的编译器(如 GCC 默认未开启
-O2以上)对factorial_recursive(20)也会产生 20 层调用 - 每次调用都压栈参数和返回地址,空间复杂度
O(n),而循环是O(1) - 调试时递归栈帧容易掩盖真实问题,比如忘了处理
n == 0
别忽略 0! 的定义和类型选择
数学上 0! == 1,代码里必须显式支持,不能靠循环“跳过”。另外,返回类型不能拍脑袋选 int —— 即使只算到 10!(3628800),在嵌入式或旧系统上 int 可能只有 16 位(最大 32767),10! 就已溢出。
立即学习“C++免费学习笔记(深入)”;
- 保守起见,输入
int n,返回用long long,并文档注明“仅支持n ∈ [0, 20]” - 若需更大范围,必须引入
std::vector手动模拟大数乘法,或用boost::multiprecision - 模板化不是万能解药:
template无法自动规避底层类型的溢出T factorial(int n)
实际项目里,阶乘很少孤立存在;它常是组合数、泰勒展开等的一部分。这时候更该考虑是否真的需要完整阶乘值,还是可以边算边约分——那才是真正的性能关键点。











