#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后溢出堆栈有人能说出如何解决这个问题吗?
答案 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;
}
这仍然会比在循环中返回常量或递增而消耗更多的运行时资源,如果将所需的常量增加到一个更大的数字,则需要增加堆栈大小。