深入解析内存分区:堆区、栈区、全局区、常量区与代码区的详细区别
1.首先,看一下内存中的分区情况:

堆区一般是由程序员手动进行分配和释放的。如果程序员没有释放堆区的内存,那么在程序结束的时候,操作系统将会对其进行回收。
栈区是由编译器自动进行分配和释放的。它用来存放函数的参数值以及局部变量的值等。其操作方式与数据结构中的栈较为类似。
全局区中,全局变量与静态变量的存储是放在一起的。初始化过的全局变量以及静态变量处于一块区域,而未初始化的全局变量和未初始化的静态变量则在相邻的另一块区域(BSS)。当程序结束后,这些区域会由系统进行释放。
④常量区:常量字符串就是放在这里的。 程序结束后由系统释放
⑤代码区:存放函数体的二进制代码。
2.全局变量和栈变量
全局变量是指不在任何函数体内(包含 main 函数)定义的变量。这种变量会被分配一个位于全局区的内存空间。一个全局变量会自动进行初始化,如果没有赋予初值的话。自动初始化的效果是将分配的内存中的每一位都设置为 0。所以当变量类型为数值型时,其值为 0;当变量类型为字符型时,其值是“空字符”;当变量类型为指针类型时,其值是 NULL。
栈变量是在函数体内(包含 main 函数)通过定义的方式来分配内存空间的变量。比如:void f(){int a;}
此时 a 的内存被分配在栈中,栈上的内存不会自动进行初始化。这意味着,如果在使用该变量之前没有给它赋予初始值,那么它将是一个随机的值,这个值是操作系统上次使用后遗留下来的。
3.堆内存
在 C 语言里,堆内存能够借助 malloc 函数去获取。这个函数会返回一个 void* 类型的指针。这个指针能够被强制转换为其他任何类型的指针。它所分配的内存不会被初始化。
下面通过综合例子来看看编译器和运行时是怎样为我们的程序分配内存的。
情况一:
该 ch 变量将被分配到内存全局区,且分配的内存会全部初始化为二进制的 0,意味着 ch 为空字符。同时,s 变量也会被分配到内存全局区,其分配的内存也全部初始化为二进制的 0,即 s 为 0。
情况二:
此时内存分配情况如下图示:
要注意 cArray 和 array 之间的区别。
“计算区域”的含义如下:在栈区中,不存在看上去似乎存在的“指针”,而是依据某种规则进行计算从而得到地址。这意味着数组名能够转换为指针,但它自身并非指针。例如,对一个数组名进行++操作时,此操作会报错。
对各个变量输出地址如下:
上图也从侧面印证了上面的内存分布图。
情况三:
此时内存分配情况如下所示:
对于这种多维 malloc 的情况,需要从内部开始向外释放已分配的内存。具体如下:
到此,基本情况展示完毕。从内存的角度去看程序,会别有一番风味。