【发布时间】:2011-07-31 03:26:21
【问题描述】:
我听说过一个神话,当“堆栈溢出”时,无限循环或没有停止条件的递归函数将停止。对吗?
例如:
void call()
{
call();
}
或
for(;;){;}
堆栈溢出时它们真的会停止吗?
更新:如果真的停止了,我可以在多少次递归调用后检测到?
【问题讨论】:
标签: recursion stack-overflow infinite-loop
我听说过一个神话,当“堆栈溢出”时,无限循环或没有停止条件的递归函数将停止。对吗?
例如:
void call()
{
call();
}
或
for(;;){;}
堆栈溢出时它们真的会停止吗?
更新:如果真的停止了,我可以在多少次递归调用后检测到?
【问题讨论】:
标签: recursion stack-overflow infinite-loop
这真的取决于语言的选择。
在某些语言中,您的无限递归函数将根据系统或语言相关条件因堆栈溢出而停止。原因是函数调用和返回的许多实现为每个函数调用分配新空间,当空间用完时程序将失败。但是,其他语言(Scheme 和各种 gcc 优化级别)实际上会让这个程序永远运行,因为它们足够聪明,可以实现每次调用都可以重用空间。
在某些语言中,无限循环将永远运行。您的程序将继续运行,永远不会取得进展。在其他语言中,编译器允许优化无限循环。例如,C++ 标准规定编译器可以假设任何循环都将终止或执行一些全局可见的操作,因此如果编译器看到无限循环,它可能只是优化循环不存在,所以循环确实终止了。
换句话说,这真的取决于。这个问题没有固定的答案。
希望这会有所帮助!
【讨论】:
您的第一个示例是递归方法调用 - 每次调用 call(在大多数语言和环境中)都会创建一个新的堆栈帧,最终您将用完堆栈(您将获得堆栈溢出条件)。
您的第二个示例不涉及递归方法调用 - 它只是一个循环。无需创建栈帧,栈不会溢出。
试一试您的示例 - 第一个示例导致堆栈溢出的速度比您想象的要快。第二个会让你的粉丝旋转得非常快,但除非你杀死它,否则什么都不会发生。
【讨论】:
取决于您使用的语言,当达到最大内存分配或最大执行时间时,循环将结束。某些语言会检测到无限循环并阻止它运行。
附言这不是神话。你可以试试看。
【讨论】:
“更新:如果真的停止了,我可以检测多少次递归调用后?”
你当然可以:
call(int n){
print(n)
call (n+1)
}
然后只需调用:
call(1)
发生堆栈溢出时,查看最后打印的数字。这是您的方法调用次数。
希望这会有所帮助!
NS
【讨论】:
无论使用哪种语言,当我创建一个可能无限的循环时,我总是会在其中建立一个“紧急出口”。我已经在 C#、VB.Net、VBA、JAVA 中完成了这项工作,而且现在是第一次在 IBM DB2 SQL 函数中完成。
由于这个概念在任何语言中都是有效的,我将用伪代码表示它,如下所示:
Begin Procedure
Declare Variable safety_counter As Integer
Begin loop
...
<body of code>
If some_criteria = True Then <-- this is your normal exit
Exit Loop
End If
...
safety_counter = safety_counter + 1
If safety_counter >= 1000 <-- set to any value you wish
Exit Loop <-- this is the emergency exit
End If
End Loop
一些变化如下。
如果循环很简单,两个退出条件可能会写在同一个 If-Then 中:
If some_criteria = True Then <-- normal exit
Or safety_counter >= 1000 <-- emergency exit
Exit Loop
End If
safety_counter = safety_counter + 1
可能会返回如下错误值:
Begin Procedure
Declare Variable result_value As Integer
Declare Variable safety_counter As Integer
Begin loop
...
<body of code>
If some_criteria = True Then <-- this is your normal exit
Set result_value = abc * xyz <-- the value you seek
Exit Loop
End If
...
safety_counter = safety_counter + 1
If safety_counter >= 1000 <-- set to any sufficient value
Set result_value = (-123) <-- indicate "infinite loop error"
Exit Loop <-- this is the emergency exit
End If
End Loop
Return result_value
有很多可能的方法可以做到这一点,但关键是在safety_counter,以及监控它以触发紧急出口的方式。
【讨论】: