堆栈内存使用算术和递归函数调用

时间:2011-01-27 12:15:01

标签: c memory recursion

我关心的是在涉及算术和递归函数调用的指令中将使用堆栈内存,例如:

return 5 + f(a-1); //f is recursive

我想了解堆栈上的内容,以及何时,以便我知道在深度递归的情况下哪些内容可能会导致内存问题。这是一个更完整的例子:

int f(int a) {
    if (a > 0) {
        return 5 + f(a-1);
    }
    else {
        return 0;
    }
}

让我们专注于return 5 + f(a-1);这一行我们将在那个点附近存储什么?

  • 我们确实在堆栈中有一个整数a的位置,因为变量是f
  • 的本地变量
  • 是否会存储值5和1?
  • 操作a-1的结果怎么样,它会被放到堆栈上?
  • f?
  • 的返回值怎么样?

关于所使用的内存量的“最坏情况”场景将是在某些时候所有这些将同时在堆栈上。更好的情况是将按顺序进行分配和释放,这样就不会将所有内容都保存在内存中。

怎么会发生?是由编译器决定的吗?

非常感谢,

4 个答案:

答案 0 :(得分:3)

如果保持递归,则必须在堆栈上至少有一个堆栈空间(例如,先前的堆栈指针或等效寄存器,用于维护堆栈帧,返回地址和空间)返回值)和传入的a-1变量。51几乎肯定不会进入堆栈,它们最有可能在代码中被硬编码

这可能看起来不多,但如果你打电话给f(999999999),你就会杀死你的筹码。递归不适合a-1 - 类型的操作。

但是,您的编译器可能足够聪明,可以对此进行尾端递归优化:

int f(int a) {
    if (a <= 0) return 0;
    return 5 + f(a-1);
}

当然,我假设你的代码只是一个样本,因为我认为它可能会被非递归甚至非迭代所取代:

int f(int a) { return (a > 0) ? a * 5 : 0; }

: - )

答案 1 :(得分:2)

此上下文中的“堆栈”也可以是内部CPU寄存器/缓存,具体取决于CPU和编译器。我会把它们全部称为堆栈以保持简单。

存储在堆栈上的东西每个函数调用是: - 变量a。 - 返回值。 - 呼叫者的返回地址。 - 可能是“条件代码寄存器”或等效的基本CPU寄存器,具体取决于体系结构。可能还有程序计数器等。即每次调用函数时都会得到的静态开销。

表达式

  

返回5 + f(a-1);

5是一个常量,它将存储在程序存储器中,不会影响堆栈。 -1很可能会被转换为汇编程序指令“减1”,因此也会在程序存储器中结束。

表达式a-1的结果将存储在堆栈中,结果将成为下一次递归的“新a”。

总结一下,在这种情况下,罪魁祸首并不是你在堆栈上来回显示的变量,而是函数调用开销所需的堆栈空间。

答案 2 :(得分:0)

查看此网站有关C Function Call Conventions and the Stack

的信息

此外,如果您担心堆栈溢出并且您的编译器无法优化tail recursion,您可以通过将tail转换为while循环或在案例中将代码转换为非递归替代方法非尾递归函数你应该能够自己创建和管理堆栈数据结构(参见Way to go from recursion to iteration

上帝保佑!

答案 3 :(得分:-3)

据我了解,这将会发生:

  • a必须放在堆栈上,因为它是一个局部变量。
  • 当然,f的参数必须放在堆栈上。
  • 值5应放在堆栈上,因为需要保存它以用于以后的+操作。
  • 如果我没记错的话,返回值会被视为参数,所以它也会被放在堆栈上。
  • 当然还有指令指针。

但也许编译器做了一些我不知道的优化。