C++内存分配中一个有趣的小问题(原来博客园已经发布的文章不能重新用markdown来写呀)
以下代码测试环境:vs2019
问题的提出
执行这么一段代码,看看会发生什么:
int main()
{
int arr[5] = { 0 };
arr[5] = 1;
}
毫无疑问,会报错,因为访问越界了。
再看看另一段代码:
int arr[5] = { 0 };
int main()
{
arr[5] = 1;
}
与上面的代码相比几乎没什么差别,仅仅把arr的定义和初始化搬到了函数外面,但执行程序却没有出错。
类似的还有这么一段代码:
int main()
{
static int arr[5] = { 0 };
arr[5] = 1;
}
同样也能执行成功,那么这是为什么呢?
问题的探索
在
C++
中内存分为5个区,分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。
堆:堆是操作系统中的术语,是操作系统所维护的一块特殊内存,用于程序的内存动态分配,C
语言使用malloc
从堆上分配内存,使用free
释放已分配的对应内存。
栈:在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
自由存储区:自由存储区是C++
基于new
操作符的一个抽象概念,凡是通过new
操作符进行内存申请,该内存即为自由存储区。
全局/静态存储区:这块内存是在程序编译的时候就已经分配好的,在程序整个运行期间都存在。例如全局变量,静态变量。
常量存储区:这是一块比较特殊的存储区,他们里面存放的是常量(const)
,不允许修改。
上面的问题涉及到两个区:栈和全局/静态存储区。
个人的推测
基于以上结果,我有个不成熟的小推测:
- 栈的空间是系统预定分配好的,假如我定义了
int arr[5]
,那么系统就一定给我5*4(32位系统下)个字节的空间,系统不允许我访问超过这个空间的地址上的数据。 - 全局/静态存储区则不同,当我定义
int arr[5]
时,系统给我返回arr
的首地址,我不仅可以根据这个首地址去访问20个字节的内容,还可以访问这二十个字节以外的内容。