无限循环和没有停止条件的递归函数何时最终停止?
我听到一个神话说无限循环或没有停止条件的递归函数将在“堆栈溢出”时停止。对吗?
例如:
void call()
{
call();
}
或者
for(;;){;}
当堆栈溢出时它们真的会停止吗?
更新:如果真的停止了,我可以检测到递归调用了多少次之后吗?
I heard a myth saying that infinite loop or a recursive function with no stop condition will stop when "the stack overflows". Is it right?
For example :
void call()
{
call();
}
or
for(;;){;}
Will they really stop when the stack overflows?
Update: If it really stops, can I detect after how many recursive calls?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
这实际上取决于语言的选择。
在某些语言中,无限递归函数将根据系统或语言相关条件因堆栈溢出而停止。原因是许多函数调用和返回的实现为每个函数调用分配新的空间,当空间耗尽时程序将失败。然而,其他语言(Scheme 和各种 gcc 优化级别)实际上会让这个程序永远运行,因为它们足够聪明,意识到它们可以为每个调用重用空间。
在某些语言中,无限循环将永远运行。你的程序只会继续运行,永远不会取得进展。在其他语言中,编译器允许优化掉无限循环。举个例子,C++ 标准规定编译器可以假设任何循环都会终止或执行一些全局可见的操作,因此如果编译器看到无限循环,它可能会优化该循环以使其不存在,因此循环实际上确实终止了。
换句话说,这确实取决于。这个问题没有硬性的答案。
希望这有帮助!
It really depends on the choice of language.
In some languages, your infinite recursive function will halt with a stack overflow based on system- or language-dependent conditions. The reason for this is that many implementations of function call and return allocate new space for each function call, and when space is exhausted the program will fail. However, other languages (Scheme and various gcc optimization levels) will actually have this program run forever because they are smart enough to realize that they can reuse the space for each call.
In some languages, infinite loops will run forever. Your program will just keep on running and never make progress. In other languages, infinite loops are allowed to be optimized away by the compiler. As an example, the C++ standard says that the compiler is allowed to assume that any loop will either terminate or make some globally-visible action, and so if the compiler sees the infinite loop it might just optimize the loop out of existence, so the loop actually does terminate.
In other words, it really depends. There are no hard-and-fast answers to this question.
Hope this helps!
您的第一个示例是递归方法调用 - 每次调用
call
(在大多数语言和环境中)都会创建一个新的堆栈框架,最终您将耗尽堆栈(您将得到一个堆栈溢出条件)。您的第二个示例不涉及递归方法调用 - 它只是一个循环。不需要创建栈帧,栈也不会溢出。
尝试一下您的示例 - 第一个示例导致堆栈溢出的速度比您想象的要快。第二个会让你的风扇旋转得非常快,但在你杀死它之前什么也不会发生。
Your first example is a recursive method call - each invocation of
call
(in most languages and environments) will create a new stack frame, and eventually you'll run out of stack (you'll get a stack overflow condition).Your second example involves no recursive method invocation - it's just a loop. No stack frames need to be created, and the stack won't overflow.
Give your examples a shot - the first example will cause a stack overflow faster than you may think. The second will make your fans spin really fast, but nothing will happen otherwise until you kill it.
根据您使用的语言,循环将在达到最大分配内存或最大执行时间时结束。有些语言会检测到无限循环并阻止其运行。
ps 这不是神话。你其实可以尝试一下。
Depends on which language you are using, the loop will end when maximum memory allocated or max execution time is reached. Some languages will detect infinite loop and stop it from running.
p.s. It is not a myth. You can actually try it.
“更新:如果真的停止了,我可以在递归调用多少次后检测到吗?”
您当然可以:
然后只需调用:
当堆栈溢出发生时,查看最后打印的数字。这是您的方法调用次数。
希望这有帮助!
NS
"Update: If it really stops, can I detect after how many recursive calls?"
You most certainly can:
Then just call:
When the stack overflow occurs, look at the last printed number. This was the number of method calls you had.
Hope this helps!
N.S.
无论使用哪种语言,当我创建一个可能无限的循环时,我总是在其中构建一个“紧急出口”。我已经在 C#、VB.Net、VBA、JAVA 中完成了此操作,而现在是第一次在 IBM DB2 SQL 函数中完成此操作。
由于这个概念在任何语言中都有效,因此我将以伪代码的形式呈现它,如下所示:
一些变体如下。
如果循环比较简单,两个退出条件可能会写在同一个 If-Then 中:
可能会返回一个错误值,如下所示:
可能的方法有很多种,但关键在于 safety_counter 以及监控的方式它触发紧急出口。
No matter the language, when I create a loop that is potentially infinite, I always build an "emergency exit" into it. I've done this in C#, VB.Net, VBA, JAVA, and just now for the first time in an IBM DB2 SQL function.
Since the concept is valid in any language, I'll present it in pseudocode, as follows:
Some variations are as follows.
If the loop is simple, the two exit criteria might be written in the same If-Then:
An error value might be returned like this:
There are many possible ways to do this, but the key is in safety_counter, and the way of monitoring it to trigger the emergency exit.