递归阶乘易栈溢出,仅适用于n

递归写法:factorial(n) 容易栈溢出
递归求阶乘最直观,但 n 稍大(比如超过 10000)就可能触发栈溢出——不是算法错,是系统默认栈空间不够。编译器不会提前警告,运行时直接 Segmentation fault。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 只在
n 且明确知道调用深度可控时用递归,比如教学演示或嵌入式小函数 - 必须加边界检查:
if (n - 别写成
return n * factorial(n-1);而不处理n == 0或n == 1,否则无限递归 - GCC/Clang 下可加
-fsanitize=address,undefined捕获越界和未定义行为
循环写法:for 实现更稳,但要注意整数溢出
循环版本没有调用栈压力,适合任意大小的 n(只要不超数据类型上限)。但 C++ 内置类型如 int、long long 很快会溢出:比如 20! = 2432902008176640000 已超出 int 范围,21! 就开始错。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 优先用
unsigned long long,它能算到20!(准确值),21!开始溢出 - 如果需要更大阶乘,必须换大数库(如
boost::multiprecision::cpp_int)或手写数组模拟 - 别用
float或double存阶乘结果——精度丢失严重,22!以上就不是整数了 - 循环起始点写
result = 1; for (int i = 2; i ,比从 1 开始多乘一次更清晰
constexpr 阶乘:编译期计算,但仅限小 n
用 constexpr 函数能在编译时算出阶乘,运行时零开销。但它受编译器递归深度限制(GCC 默认约 512 层),实际能算的 n 很小,且错误发生在编译阶段,报错信息常是 constexpr evaluation exceeded maximum depth。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 只用于
n 的常量场景,比如数组长度、模板参数 - 必须确保所有输入都是字面量或
constexpr变量,运行时变量传入会退化为普通函数调用 - VS 和 GCC 对
constexpr递归支持略有差异,跨平台项目建议加static_assert(n
模板元编程阶乘:编译期暴力展开,难调试
用模板特化实现阶乘(如 factorial::value)完全在编译期完成,无运行时成本。但它会让编译时间变长、错误信息极难读,而且每个 n 都生成独立实例,代码膨胀明显。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 除非写泛型库或对性能极端敏感(比如嵌入式启动代码),否则没必要上模板元编程
- 错误常表现为
template instantiation depth exceeds maximum,调高限制(如-ftemplate-depth=1024)只是掩耳盗铃 - 现代 C++ 更推荐用
constexpr if+ 普通函数替代,可读性和维护性高得多
真正麻烦的从来不是“怎么写”,而是“怎么选”:小 n 用递归图个清楚;中等 n(≤20)用 constexpr;大 n 必须接受大数库或自己处理溢出逻辑。没人会在生产环境用裸 int 算 100!,但新手常卡在“为什么输出是负数”这种问题上——那只是溢出,不是 bug。










