0Pricing
C Academy · 课时

避免栈溢出

限制递归的深度。

避免栈溢出 是 CoddyKit 上的免费 C Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C Academy 课程共包含 4 节课。

什么是栈溢出

调用栈的大小是有限的。每次函数调用都会为参数和局部变量占用其中一部分空间。

如果递归过深,栈就会被填满,程序会因栈溢出而崩溃。

缺少基本情况

最常见的原因是基本情况永远无法达到。这会导致无限循环,最终栈溢出。

不要运行这类函数;请研究它失败的原因。

int broken(int n) {
    /* no base case: never stops */
    return broken(n + 1);
}

参数没有缩小

即使存在基本情况,参数也必须朝着它变化。在这里 n 不断增大,因此永远无法达到 0。

请始终检查每次调用是否都更接近停止条件。

int oops(int n) {
    if (n == 0) return 0;
    return oops(n + 1); /* wrong direction */
}

正确的版本

修正变化方向后,函数就会终止。现在 n 会递减并趋向基本情况 0。

#include <stdio.h>

int good(int n) {
    if (n == 0) return 0;
    return n + good(n - 1);
}

int main(void) {
    printf("%d\n", good(10));
    return 0;
}

深度限制确实存在

即使递归逻辑正确,递归过深也可能导致栈溢出。调用一个数百万层深的函数可能超过栈的容量,而栈通常只有几兆字节。

对于非常大的深度,请优先使用迭代。

将深度递归转换为循环

如果递归深度会随着输入规模增长,请改用循环。这样可以避免堆叠数千个栈帧。

下面的循环使用固定大小的内存,安全地计算从 1 加到很大的 n。

#include <stdio.h>

int main(void) {
    long total = 0;
    for (int i = 1; i <= 1000000; i++)
        total += i;
    printf("%ld\n", total);
    return 0;
}

使用分治减少深度

将工作量分成两半可以保持较小的深度。通过不断二分范围来求和时,深度的增长速度类似于规模的对数,而不是线性增长。

long range_sum(int lo, int hi) {
    if (lo == hi) return lo;
    int mid = (lo + hi) / 2;
    return range_sum(lo, mid) + range_sum(mid + 1, hi);
}

注意大型局部数组

Big 局部变量会让每个栈帧都更 heavy,因此栈会更快填满。

请避免在递归函数内部声明大型数组;改为传递指针,或使用堆。

void heavy(int n) {
    int buffer[10000]; /* big frame each call */
    if (n == 0) return;
    heavy(n - 1);
}

使用累加器

将当前总和作为累加器传递,可以使每个栈帧保持较小,并让递归呈现尾递归结构。

这样一来,某些编译器就可以重用同一个栈帧。

#include <stdio.h>

long sum_acc(int n, long acc) {
    if (n == 0) return acc;
    return sum_acc(n - 1, acc + n);
}

int main(void) {
    printf("%ld\n", sum_acc(100, 0));
    return 0;
}

安全检查清单

在信任一个递归函数之前,请检查:

1. 是否存在基本情况?
2. 每次调用是否都会朝着基本情况变化?
3. 对于大规模输入,深度是否可能非常大?

如果深度可能急剧增长,请改用循环。

使用小规模输入进行测试

请始终先使用可以手动验证的极小输入测试递归。

如果小规模情况能够正常工作,并且深度保持有界,您就可以放心扩大规模。

快速检查

找出最安全的修复方法。

回顾

递归过深或永不停止时,就会发生栈溢出。请始终提供一个可以达到的基本情况,让参数在每次调用中缩小,保持栈帧轻量,并在深度可能随输入规模增长时切换到迭代。

常见问题解答

「避免栈溢出」课时是免费的吗?

是的 — 「避免栈溢出」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C Academy 课程的其余内容,请升级到 CoddyKit PRO。 C Academy 课程共包含 4 节课。

「避免栈溢出」这节课中我会学到什么?

限制递归的深度。 你通过在浏览器中直接运行的动手代码来练习 C Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 C Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 C Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「避免栈溢出」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 C Academy 课中编写并运行代码吗?

能。每节 C Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 递归的工作原理
  2. 经典递归问题
  3. 递归与迭代
  4. 避免栈溢出
← 返回 C Academy