C 在用户可编程计算器中防止堆栈溢出/无限递归

C 在用户可编程计算器中防止堆栈溢出/无限递归,c,recursion,stack-overflow,C,Recursion,Stack Overflow,我写了一个用户可编程计算器,现在我遇到了以下问题 假设用户在其中写入以下内容: fun(n) = fun(n-1) 然后尝试拨打fun(42)(或任何号码)。现在很明显,用户的代码将导致无限递归,这反过来会导致整个计算器因堆栈溢出而崩溃 我怎样才能使计算器优雅地退出计算 我看过Mathematica如何处理类似的情况,它只是说 $IterationLimit::itlim: Iteration limit of 4096 exceeded. 我尝试过类似的方法,但是,由于堆栈大小取决于操作系

我写了一个用户可编程计算器,现在我遇到了以下问题

假设用户在其中写入以下内容:

fun(n) = fun(n-1)
然后尝试拨打
fun(42)
(或任何号码)。现在很明显,用户的代码将导致无限递归,这反过来会导致整个计算器因堆栈溢出而崩溃

我怎样才能使计算器优雅地退出计算

我看过Mathematica如何处理类似的情况,它只是说

$IterationLimit::itlim: Iteration limit of 4096 exceeded.
我尝试过类似的方法,但是,由于堆栈大小取决于操作系统,我如何知道使用哪个数字作为迭代限制(是的,我通过实验找到了一个“似乎有效”的数字,但感觉不对)


谢谢你抽出时间。计算器的核心是用C语言编写的。

这只是C语言的一个丑陋的小角落——没有便携的方法来知道你可以安全地使用多少堆栈。从技术上讲,甚至不必有足够的堆栈从
main()
调用单个函数-这被认为是实现质量问题


最安全的方法是展开递归,以便它使用您使用
malloc()
分配的自己的表达式堆栈,而不是无限真正的递归。这样,如果在达到应用程序定义的递归限制之前
malloc()
返回
NULL
,您就可以退出了。

使用malloc实现您自己的基于堆的堆栈,而不是将用户级数学函数调用实现为C函数调用。这将为您提供更多级别的递归和可靠地判断故障的方法


或者,您可以对递归的级别设置一个合理的小限制。

一个快速的技巧就是跟踪递归深度,如果超过了它,就退出。一个计数器就足够了。当然,您可能需要在每次求值之间重置计数器,但它不如运行自己的堆栈那么健壮。

如果您编写计算器时不在主机本身进行递归调用,例如,您自己通过堆栈处理实现,那么该限制是任意的,取决于可分配的可用内存(以及一些内存)“sane depth”)+1用于展开递归,但如果这样做,则不应包含递归限制;只需继续执行直到malloc失败(当然,也可以完成)@David X:仅仅因为用户给了你一些不好的输入,就花30分钟填满所有可用的交换空间并最终死去,这可能被认为是反社会的。递归限制是用来捕捉错误的无限递归的(但一定要让它成为用户可调整的)。没错,我出于某种原因考虑硬编码限制。