为什么堆栈溢出

时间:2016-12-05 19:43:14

标签: c stack local-storage

在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];,则程序会因堆栈溢出(分段错误)而崩溃。

我用

尝试了这个
  • gcc-4.4.7 -O0,gcc-4.4.7 -O2,gcc-4.4.7 -O3
  • gcc-4.8.4 -O0,gcc-4.8.4 -O2,gcc-4.8.4 -O3
  • gcc-4.9.3 -O0,gcc-4.9.3 -O2,gcc-4.9.3 -O3

如果我使用

ulimit -s 1024

然后int a[2500];的版本崩溃,而int a[2500+c];的版本崩溃。

为什么使用可变长度数组(int a[2500+c];)的程序版本比使用固定长度数组(int a[2500];)的版本消耗更少的堆栈空间?

1 个答案:

答案 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;
}