在Linux下启动
ulimit -s 1024
限制堆栈大小。
首先是一个有效的程序:
#include <stdio.h>
static int calc(int c,int *array)
{
if (array!=NULL) {
if (c<=0) {
array[0]=1;
return 1;
}
calc(c-1,array);
array[c]=array[c-1]+3;
return array[c];
} else {
int a[2500+c];
calc(c-1,a);
a[c]=a[c-1]+3;
return a[c];
}
}
int main()
{
int result;
result = calc(1000,NULL);
printf("result = %d\n",result);
}
现在,如果我将int a[2500+c];
更改为int a[2500];
,则程序会因堆栈溢出(分段错误)而崩溃。
我用
尝试了这个如果我使用
ulimit -s 1024
然后int a[2500];
的版本崩溃,而int a[2500+c];
的版本崩溃。
为什么使用可变长度数组(int a[2500+c];
)的程序版本比使用固定长度数组(int a[2500];
)的版本消耗更少的堆栈空间?
答案 0 :(得分:5)
正如your previous question的评论中所提到的,“为什么”是编译器的实现细节。该标准没有规定如何布局堆栈(或者甚至是堆栈)。正如您所看到的相同编译器的不同版本,或具有不同优化设置的相同版本,可以改变编译器的工作方式。
话虽这么说,编译器可能会为函数中任何位置声明的所有变量分配堆栈空间,这些变量在输入函数时不是VLA。它可能在某种程度上对开发人员来说是不透明的。使用VLA,直到运行时才知道大小,因此它的分配方式不同。
在这种情况下,最好使用malloc而不是使用本地数组。这会给你更多确定性的行为。
....
} else {
int *a = malloc(c * sizeof(int));
if (a == NULL) {
perror("malloc failed");
exit(1);
}
calc(c-1,a);
a[c]=a[c-1]+3;
int rval = a[c];
free(a);
return rval;
}