我们在做题时开数组经常会出现爆栈问题,那么这是为什么?
让我们带着问题先来了解一下C语言的内存分区,C语言内存分为五个区:
代码区:顾名思义这里是用来存储代码编译后的二进制机器码;
堆区:用于动态内存分配,一般由程序员分配或释放,如果程序员没有在程序运行中手动释放,那么会在程序结束后释放。
栈区:编译器自动分配和释放,一般用来存放局部变量、函数参数。
全局初始化数据区/静态数据区(Data Segment):用来存储全局变量和静态变量。
⑤未初始化数据区(BSS):在运行时改变值。改变值(初始化)的时候,会根据它是全局变量还是局部变量,进到他们该去的区。否则会持续待在BSS里面与世无争。(待会儿会用实验来证明并感受它的存在。)
重点说一下栈区和全局初始化数据区/静态数据区 我们常说的爆栈问题,大部分就是发生在了栈区,爆栈原因是我们定义了过大的数组栈区内存装不下了。那么我们把数组定义在了 main() 外面(也就是全局区)一般情况下不会爆栈,为什么?
原因很简单 那就是在Windows下C语言分配给栈区的内存远小于全局区,全局区的内存与电脑的剩余内存有关,我们做题所定义的变量占用的内存简直就是小儿科,但是!!!分配给栈区的内存只有 2M(接近2M) !也就是说 。。。
先说一下计算机常用内存单位之间的换算 :
1 M = 1024 KB ;1 KB = 1024Byte ; 1Byte = 8 bit
继续说:也就是说栈区只有 2 * 1024 *1024 = 2,097,152 字节 仅能储存 524,288 个int型变量(其实也不少了);但是在创建二维数组时要小心了 最大只能创建 int array[719][720] 的二维数组,否则 会爆栈;
那么为什么要把变量存储在栈区?直接储存在全局区多好?我们要这样想 它存在肯定有它存在的理由,经过查询:
栈:由系统自动分配,速度较快。但程序员是无法控制的。
堆:是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便。
经过以上的探讨对C语言的内存分配有所了解了,再讲一个小知识点(BSS区):先看一段代码:
#include<stdio.h>
int main (){
int array[518156];
printf("sucess!\n");
return 0;
}
经过测试array[518156];这是我的电脑在栈区所能定义的最大整型数组(再增加一个都不行);
理论上说这时的栈区已经满了不能再增加变量了,再看下一段代码:
#include<stdio.h>
int main (){
int array[518156];
int test1,test2,test3,test4,test5,test6;
double test7,test8,test9;
float test10,test11,test12;
char test13,test14,test15;
printf("sucess!\n");
return 0;
}
我在下面又定义了 6 个int 变量,3 个 double 变量,3 个 float 变量,3 个 char 变量 它还是没爆栈,为什么?
原因是 未赋值的 变量存储在了 BSS区 并未占用栈内存,当你 给任意个 变量(即使是最小的 char 变量) 赋了值 就会爆栈。