6

http://www-ee.eng.hawaii.edu/~tep/EE160/Book/chap14/subsection2.1.1.8.html 这个页面说局部变量和传递的参数是在堆栈上分配的,所以我尝试了:

#include <stdio.h>
#include <stdlib.h>
#define A 2000000
#define B 2

typedef struct {
    int a[A][A];
} st;

void fun(st s){}

void main()
{
    st s;
    //fun(s);
}

编译运行后没有报错。但是当我去注释时//fun(s),然后 SIGSEGV 被抓住了。谁能告诉我为什么?

4

2 回答 2

12

局部变量分配在哪里?堆还是栈?

这个页面说局部变量和传递的参数是在堆栈上分配的

确切地。

但是当我去注释 //fun(s) ,然后 SIGSEGV 被抓住了。谁能告诉我为什么?

堆栈上的内存比堆上的内存更有限¹。您正在堆栈上分配一个 2000000x2000000 数组,然后将其传递给一个函数。这很可能会超出可用的堆栈空间,从而导致分段错误。

至于为什么注释掉函数调用时不会发生分段错误。首先,正如 Jonathan Leffer 指出的那样,编译器可能会s完全优化掉,因为它没有被使用。但即使没有,您也可能不会遇到段错误,因为在堆栈上分配内存仅意味着递增堆栈指针。并且在大多数实现本身永远不会导致分段错误。只有当您尝试访问分配的内存并且系统意识到您超出了堆栈的边界(在这种情况下也是整个内存)时,才会发生分段错误。

¹尽管在这种情况下并没有什么不同,因为正如 slugonamission 指出的那样,该数组占用了 16TB,因此也会超过堆上的可用内存。

于 2013-01-26T02:18:19.297 回答
3

此外,这是一个很好的例子,为什么你只通过值传递函数参数,而通常你通过引用传递参数:

#include <stdio.h>
#include <stdlib.h>
#define A 2000000
#define B 2

typedef struct {
    int a[A][A];
} st;

void fun(st *s){}

void main()
{
    st s;
    fun(&s);
}

我认为它根本不会运行,因为它需要 4TB 的堆栈内存。由于编译器转储了未使用的变量并且根本没有在运行时声明,因此它可以//fun(s)在您的代码中顺利编译和运行。s

于 2013-01-26T02:29:29.820 回答