正在讨论的程序尝试使用递归计算第一n个自然数的和.我知道这可以使用一个简单的公式n *(n 1)/ 2,但这里的想法是使用递归.
方案如下:
#include <stdio.h> unsigned long int add(unsigned long int n) { return (n == 0) ? 0 : n + add(n-1); } int main() { printf("result : %lu \n",add(1000000)); return 0; }
该程序在n = 100,000时运行良好,但当n的值增加到1,000,000时,导致分段故障(core dumped)
以下是从gdb消息中获取的.
Program received signal SIGSEGV,Segmentation fault. 0x00000000004004cc in add (n=Cannot access memory at address 0x7fffff7feff8 ) at k.c:4
我的问题:
> C中的递归深度有没有硬连线限制?还是递归深度取决于可用的堆栈内存?
>程序会收到reSIGSEGV信号的可能原因是什么?
解决方法
通常这个限制将是栈的大小.每次调用函数时,都会吃掉一定量的堆栈(通常取决于函数).吃饭量是堆栈帧,当函数返回时它被恢复.程序启动时,堆栈大小几乎几乎固定,无论是由操作系统指定(通常可调整),甚至在程序中都被硬编码.
一些实现可能有一种技术,它们可以在运行时分配新的堆栈段.但是一般来说,他们没有.
>一些函数将以稍微更不可预测的方式消耗堆栈,例如在它们分配可变长度数组时.
>某些函数可能被编译为以保留堆栈空间的方式使用尾部调用.有时你可以重写你的函数,这样所有的调用(比如自己)就像最后一件事情一样发生,希望你的编译器能够优化它.
看到每次调用函数需要多少堆栈空间并不容易,它将受制于编译器的优化级别.在你的情况下,这样做的一个便宜方式是每次打电话时都打印出来; n可能在堆栈上(特别是因为程序需要占用地址 – 否则可能在寄存器中),并且它的连续位置之间的距离将指示堆栈帧的大小.