递归C ++函数中的Stack Overflow错误

时间:2013-09-20 18:27:20

标签: c++

#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;
}

这个函数在count值超过4800后溢出堆栈有人能说出如何解决这个问题吗?

3 个答案:

答案 0 :(得分:5)

不要使用递归 - 使用常规循环。每当你调用f()方法时,你将在堆栈上占用几个字,并且你会在某些时候溢出它。

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

或者只是int f(){ return 5000; }会这样做。

答案 1 :(得分:3)

假设你想以递归方式运行,你可以关闭调试模式,然后你就会成功(因为Visual Studio会在堆栈上添加额外的东西来检测你是否“破坏”堆栈[它是怎么说的“堆栈变量x周围被覆盖“或者无论确切的消息是什么]。

然而,依赖于能够递归地执行大量呼叫是一个糟糕的计划 - 在某些时候,它仍然会倒下。无论是5000,50000还是500000只是“这个功能需要多少堆栈空间”的问题。我会说任何不具有大约100级递归的自然限制的情况都是“你以错误的方式解决问题”。如果确实有如此大的递归级别,最好使用软件堆栈(例如C ++中的std::stack),并将crrent状态保存在该堆栈上,并使用函数内的软件将其恢复。

耗尽堆栈空间是最糟糕的运行时问题之一,因为你真的没有什么可以做的 - 你可以做些什么来打印错误信息或者其他一些问题,但实际上没有办法“给出这个过程多了一些堆栈空间并继续“。当一个进程耗尽内存或类似的东西时,你可以说“好吧,我不会分配它,并给用户一个很好的错误信息,说'我做不到',并很好地保存当前状态和退出,例如。“

[是的,你可以增加你的应用程序的堆栈大小,但这真的应该只是作为一个真正的最后手段,并且只有当你完全理解为什么你需要这么大的堆栈 - 它往往是你的其他东西如果你需要更大的堆栈,那就错了。

答案 2 :(得分:1)

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

编写函数的更好方法:

#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;
}

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