今天在写代码的时候,偶然发现一个问题:在main函数中定义较大的数组变量,一运行程序就会崩溃

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <bits/stdc++.h>
using namespace std;
const int N = 1010;

int main(){
int arr[N][N]; // 运行时错误:segment fault
for(int i=1;i<N;++i){
for(int j=1;j<N;++j){
arr[i][j]=i*j;
}
}
return 0;
}

segment_fault

但是,当这个数组作为全局变量时,又不会出现这个错误。

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
int arr[N][N]; // 作为全局变量

int main(){
for(int i=1;i<N;++i){
for(int j=1;j<N;++j){
arr[i][j]=i*j;
}
}
return 0;
}

原本以为是个什么玄学问题,后来搜索相关资料才明白,原来是栈溢出了。

int arr[N][N] 定义在函数内时,它是作为局部变量,在中分配空间的。而系统中为栈分配的空间都是比较小的(windows中有的是2MB,跟平台也有关),例如这里 N=1010,int的大小为 4Byte,那么arr的空间也接近4MB了,超出了栈的大小,所以才会出现问题(当然,N设置的比较小是不会有问题的)。

那么为了避免栈空间溢出,可以:

  1. 把 arr数组 作为全局变量,在全局区分配空间就不受栈空间大小的限制了;
  2. 使用堆来分配数组空间,例如new动态分配,使用std::vector等(注意,std::array 也是在栈中分配空间的)。

同时,注意到栈使用的是一级缓存,而堆使用的二级缓存,栈的速度是要大于堆的速度的。所以,通过上述案例,可以帮助我们更高效地运用栈,即总结如下:

  • 当数据量小时,可以将其开辟在栈中,提高效率;
  • 当数据量大时,栈中无法存储大量的数据,那么只能存放在堆中。