C++ 递归函数引起的堆栈溢出
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15976333/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Stack overflow caused by recursive function
提问by charles
Being a beginner to C++ programming and computer systems architecture, I'm still learning the basics of C++. Yesterday I read about recursive function, so I decided to write my own, here's what I wrote : (very basic)
作为 C++ 编程和计算机系统架构的初学者,我仍在学习 C++ 的基础知识。昨天我读到了递归函数,所以我决定自己写,这是我写的:(非常基本)
int returnZero(int anyNumber) {
if(anyNumber == 0)
return 0;
else {
anyNumber--;
return returnZero(anyNumber);
}
}
}
And when I do this : int zero1 = returnZero(4793 ); it causes a stack overflow, however, if I pass the value 4792 as parameter, no overflow occurs.
当我这样做时: int zero1 = returnZero(4793 ); 它会导致堆栈溢出,但是,如果我将值 4792 作为参数传递,则不会发生溢出。
Any ideas as to why ?
关于为什么的任何想法?
回答by NPE
Whenever you call a function, including recursively, the return address and often the arguments are pushed onto the call stack. The stack is finite, so if the recursion is too deep you'll eventually run out of stack space.
每当您调用函数时,包括递归调用,返回地址和参数通常会被推送到调用堆栈上。堆栈是有限的,因此如果递归太深,您最终会耗尽堆栈空间。
What surprises me is that it only takes 4793 calls on your machine to overflow the stack. This is a pretty small stack. By way of comparison, running the same code on my computer requires ~100x as many calls before the program crashes.
让我感到惊讶的是,在您的机器上只需要 4793 次调用即可溢出堆栈。这是一个非常小的堆栈。相比之下,在我的计算机上运行相同的代码需要大约 100 倍的调用次数才能让程序崩溃。
The size of the stack is configurable. On Unix, the command is ulimit -s
.
堆栈的大小是可配置的。在 Unix 上,命令是ulimit -s
.
Given that the function is tail-recursive, some compilers might be able to optimize the recursive call away by turning it into a jump. Some compilers might take your example even further: when asked for maximum optimizations, gcc 4.7.2
transforms the entire function into:
鉴于该函数是tail-recursive,一些编译器可能能够通过将其转换为跳转来优化递归调用。一些编译器可能会更进一步:当被要求进行最大优化时,gcc 4.7.2
将整个函数转换为:
int returnZero(int anyNumber) {
return 0;
}
This requires exactly two assembly instructions:
这正好需要两条汇编指令:
_returnZero:
xorl %eax, %eax
ret
Pretty neat.
漂亮整齐。
回答by óscar López
You just hit the call stack's size limit of your system, that's what's happening. For some reason the stack in your system is tiny, a depth of 4793 function calls is rather small.
您刚刚达到了系统调用堆栈的大小限制,这就是正在发生的事情。由于某种原因,您系统中的堆栈很小,4793 个函数调用的深度相当小。
回答by Shafik Yaghmour
Your stack is limited in size and so when you make 4793
calls you are hitting the limit while 4792
just comes in under. Each function call will use some space on the stack for house keeping and maybe arguments.
您的堆栈大小有限,因此当您4793
拨打电话时,您正在达到限制而4792
刚刚进入。每个函数调用都会使用堆栈上的一些空间来进行内部管理,也可能是参数。
This page gives an exampleof what a stack looks like during a recursive function call.
此页面提供了一个示例,说明在递归函数调用期间堆栈的外观。
回答by Michael Dorgan
My guess is you stack is exactly big enough to fit 4792 entries - today. Tomorrow or the next, that number might be different. Recursive programming can be dangerous and this example illistrates why. We try not to let recursion get this deep or 'bad' things can happen.
我的猜测是您的堆栈完全足够容纳 4792 个条目 - 今天。明天或下个月,这个数字可能会有所不同。递归编程可能很危险,这个例子说明了原因。我们尽量不让递归变得如此深入或“坏”的事情可能发生。
回答by Mats Petersson
Any "boundless" recursion, that is recursive calls that aren't naturally limited to a small(ish) number will have this effect. Exactly where the limit goes depends on the OS, the environment the function is called in (the compiler, which function calls the recursive function, etc, etc).
任何“无限”递归,即自然不限于小(ish)数的递归调用都会产生这种效果。限制的确切位置取决于操作系统、调用函数的环境(编译器、哪个函数调用递归函数等)。
If you add another variable, say int x[10];
to your function that calls your recursive function, the number needed to crash it will change (probably by about 5 or so).
如果你添加另一个变量,比如int x[10];
你的函数调用你的递归函数,它崩溃所需的数量会改变(可能大约 5 左右)。
Compile it with a different compiler (or even different compiler settings, e.g. optimization turned on) and it will probably change again.
使用不同的编译器(甚至不同的编译器设置,例如打开优化)编译它,它可能会再次更改。
回答by Sufiyan Ansari
Using recursion, you can achieve SuperDigit:
使用递归,你可以实现 SuperDigit:
public class SuperDigit
{
static int sum = 0;
int main()
{
int n = 8596854;
cout<<getSum(n);
}
int getSum(int n){
sum=0;
while (n > 0) {
int rem;
rem = n % 10;
sum = sum + rem;
n = n / 10;
getSum(n);
}
return sum;
}
}