可能很多人都有这样一个疑问:数组的最大可定义长度到底是多少?
网上众说纷纭:有些说跟内存大小,或者说栈大小、堆大小什么的。
今天在这里总结一下。大家如果觉得ok理解了,麻烦点个赞哟~
首先,如果要确定一个数组的最大长度,我们需要知道它的数据类型,因此,数组的数据类型是其中一个限制因素。因为不同数据类型的元素大小不同。很显然(我们假设
int
为4字节,char
为1字节),数据类型为char
的数组的最大长度是类型为int
的数组的4倍。
另外,不难想到,大小(size)的数据类型,也就是数组下标的数据类型,其实也是一个限制因素。在C/C++中,数组下标的类型是
std::size_t
,因此数组的大小首先不能超过size_t
所能表示的大小。这个数据类型是在库文件stdio.h
中通过typedef
声明的,对于32位程序它被定义为unsighed int
,对于64位程序定义为unsigned long
。前者能表示的最大大小为2^32-1,后者为2^64-1。
然后,size也限制于物理内存的大小。这一点不用细说,因为程序运行时一旦超过物理内存的大小,这个程序就会立刻崩溃。
下面详细展开:
-
大家应该都知道,数组的分配方式大概有两种方式:静态分配和动态分配。再具体点儿的话,根据数组声明的位置,我们可以将数组分为局部数组和全局数组。这样讨论的话,就复杂了,我们暂时可以将数组分为四类(只是笔者本人这样划分,不知道官方是否有这样的分类):
1、静态分配的局部数组、
2、动态分配的局部数组、
3、静态分配的全局数组、
4、动态分配的全局数组。
-
静态分配的局部数组,使用的是栈上的空间,因此静态分配得到的局部数组的大小受限于栈的大小。具体来说是数组所在函数栈帧的大小,当然栈帧的大小肯定不能超过栈的大小。如果你对编译器的使用比较熟悉或者你阅读过编译器文档的话,你应该知道如何调整栈帧的大小限制。在WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将会提示溢出。
-
一般一个进程的栈空间是2M,所以你定义过大的int型数组肯定直接溢出。可以算一下:
一个int占4字节,如果定义数组的话,那么2M/4=500K,当然进程启动本身就要很多东西要入栈,所以比500K要小。500K=500,000B,所以可以认为int数组的最大范围是500,000(估计),char类型的最大范围是2000,000。 -
PS:这里的B是指字节。int是4字节:也就是4*8=32位。所以int的理论最大值是 2^32 -1。但是因为要考虑正负号,所以实际上是:-2147483648~2147483647[-2^31~2^31-1]。int的大小与计算机的数据字长,和编译器都相关;而数组的大小由栈空间,int的大小决定;所以综上:数组的最大长度由进程栈空间,计算机数据字长,编译器决定。具体不展开了。
【总结:静态数组的大小比较小】
-
动态分配的局部数组和动态分配的全局数组,划分为一类。本质上它们都是在堆上分配空间,因此它们的大小受限于堆的大小。堆是不连续的内存区域,堆的大小受限于计算机系统中有效的虚拟内存,因此堆的大小一般都比较大。new出来的话,堆空间按照32位机器上是4G(2^32=(2^10)^3 * 4=4G),按照4G/4=1G,理论上应该比1G小点,也就是比1000000000小点(1M=1000KB=1000,000B),再大就堆溢出了。而64位机的话寻址空间大一些,所以大概有(2^64,基本上用不完了),所以64位机子可以认为动态分配永远用不完。
-
至于静态分配的全局数组,我们知道它是在静态存储区分配内存空间,因此大小自然受限于静态存储区的大小,也叫做BSS(Block Started by Symbol),在汇编语言中,我么也称之为数据段。目前我还不太清楚静态存储区的大小限制,我在我的电脑(Core i3-3110M, 内存8GB)上做过实验发现我所能分配的最大大小大约为剩余内存的1/2。网上有这样说的:“你的常量有多大就多大”,但是还有待考证。【总之这个基本上也可以设的很大】
Note:关于栈帧的概念可以参考《深入理解计算机系统》这本书,或者其他关于计算机体系结构的资料。
总结:
除了静态分配的局部数组,其他的基本上都不需要考虑上限(对于目前普遍的64位机)。