0
#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 后溢出堆栈有人能告诉如何解决这个问题吗?

4

3 回答 3

5

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

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

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

于 2013-09-20T18:30:27.857 回答
3

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

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

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

[是的,您可以增加应用程序的堆栈大小,但这确实应该作为真正的最后手段,并且只有当您完全理解为什么需要如此大的堆栈时——这通常是您正在做的其他事情如果你需要更大的堆栈,那就错了]。

于 2013-09-20T19:46:02.540 回答
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;
}

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

于 2013-09-20T18:50:30.243 回答