递归C++函数中的堆栈溢出错误

Stack Overflow error in recursive C++ function

本文关键字:堆栈 栈溢出 错误 C++ 函数 递归      更新时间:2023-10-16
#include<iostream>
using namespace std;
int f()
{
    static int count=0;
    count++;
    if (count>=5000)
        return count;
    return f();
}
int main ()
{
    cout<<f();
    return 0;
}

计数值超过 4800 后,此函数会使堆栈溢出,任何人都可以告诉如何解决此问题吗?

不要使用递归 - 使用常规循环。每次调用 f() 方法时,都会占用堆栈上的几个单词,并且会在某个时候溢出它。

通常,有办法增加堆栈大小(取决于您的系统和/或编译器),但我不想推荐这样做(特别是因为它会再次溢出,只是当 count 的值大于 4800 时)。

或者只是int f(){ return 5000; }就可以了。

假设你想递归运行,你可以关闭调试模式,那么你就会成功(因为Visual Studio在堆栈上添加了额外的东西来检测你是否"破坏"堆栈[这就是它如何说"变量周围的堆栈x被覆盖"或任何确切的消息)。

然而,依靠能够递归地进行大量调用通常是一个糟糕的计划——在某些时候,它仍然会失败。无论是 5000、50000 还是 500000,都只是"这个函数需要多少堆栈空间"的问题。我想说的是,任何没有大约 100 级递归的自然限制的东西都是"你以错误的方式解决问题"的情况。如果你确实有这么大的递归级别,最好使用软件堆栈(例如 std::stack在 C++) 中),并将 crrent 状态保存在该堆栈上,并使用函数中的软件将其恢复。

堆栈空间不足是最糟糕的运行时问题之一,因为您实际上无能为力 - 您可能可以执行某些操作来打印错误消息或类似操作,但实际上没有办法"给进程更多的堆栈空间并继续"。当进程内存不足或类似内容时,您可以说"好吧,我不会分配它,并给用户一个很好的错误消息,说'我不能这样做',然后很好地保存当前状态并退出,例如。

[是的,你可以增加应用程序的堆栈大小,但这实际上应该只作为真正的最后手段来完成,并且只有当你完全理解为什么你需要这么大的堆栈时 - 如果你需要一个更大的堆栈,这通常是你做错了什么]。

我假设这是为了学习递归的学术练习。 (如果不是,请不要为此使用递归!

编写函数的更好方法:

#include <iostream>
int f(int i)
{
    if (i >= 5000)
    {
        return i;
    }
    else
    {
        return f(i + 1);
    }
}
int f_alt1()
{
    return 5000;
}
int f_alt2()
{
    int i = 0;
    for (; i <= 5000; ++i);
    return i;
}
int main()
{
    std::cout << f(0) << std::endl;
    return 0;
}

这仍然会消耗比返回常量或在循环中递增更多的运行时资源,并且如果将所需的常量增加到一个明显更大的数字,则需要增加堆栈大小。