接触过编程的人都知道,高级语言都能通过变量名来访问内存中的数据。
1. 那么这些变量在内存中是如何存放的呢?
2. 程序又是如何使用这些变量的呢?
首先,来了解一下 C 语言的变量是如何在内存分布的。
C 语言有全局变量(Global)、本地变量(Local),静态变量(Static)、寄存器变量(Regeister)。每种变量都有不同的分配方式。先来看下面这段代码:
#include <stdio.h>
int g1=0, g2=0, g3=0; //函数外的全局变量
int main()
{
static int s1=0, s2=0, s3=0;
int v1=0, v2=0, v3=0;
//打印出各个变量的内存地址
printf("0x%08x\n",&v1); //打印各本地变量(函数内)的内存地址
printf("0x%08x\n",&v2);
printf("0x%08x\n\n",&v3);
printf("0x%08x\n",&g1); //打印各全局变量(函数外)的内存地址
printf("0x%08x\n",&g2);
printf("0x%08x\n\n",&g3);
printf("0x%08x\n",&s1); //打印各静态变量(static修饰)的内存地址
printf("0x%08x\n",&s2);
printf("0x%08x\n\n",&s3);
return 0;
}
编译后的执行结果是:
0x0012ff78 //打印各本地变量(函数内)的内存地址
0x0012ff7c
0x0012ff80
0x004068d0 //打印各全局变量(函数外)的内存地址
0x004068d4
0x004068d8
0x004068dc //打印各静态变量(static修饰)的内存地址
0x004068e0
0x004068e4
输出的结果就是变量的内存地址。其中v1,v2,v3是本地变量,g1,g2,g3是全局变量,s1,s2,s3是静态变量。
可以看到:
- 同类型变量在内存是连续分布的
- 本地变量和全局变量分配的内存地址相差较大。
- 全局变量和静态变量分配的内存是连续的。
这是因为本地变量和全局/静态变量是分配在不同类型的内存区域中的结果。对于一个进程的内存空间而言,可以在逻辑上分成3个部份:代码区、静态数据区和动态数据区。
代码区:存放函数体的二进制代码。
动态数据区:一般就是“堆栈”。“栈(stack)”和“堆(heap)”是两种不同的动态数据区,栈是一种线性结构,堆是一种链式结构。一个堆栈可以通过“基地址”和“栈顶”地址来描述。
- 栈区:存放自动变量。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元由编译器自动释放。栈存放函数的参数值,局部变量的值等。
- 堆区(自由存储区):在运行的时候调用程序(如C中的malloc或C++中的new)分配内存,可以在任何时候决定分配内存及分配的大小,用户自己负责在何时释放内存(如用free或delete)。堆中的所有东西都是匿名的,这样不能按名字访问,而只能通过指针访问。
静态数据区:存在程序启动的时候才被分配,而且可能直到程序开始执行的时候才被初始化,如函数中的静态变量就是在程序第一次执行到定义该变量的代码时才被初始化。所分配的内存在程序的整个运行期间都存在,如**全局变量和静态变量分配在静态数据区,本地变量分配在动态数据区,即堆栈中。**程序通过堆栈的基地址和偏移量来访问本地变量。**注意:**初始化的全局变量和静态变量在一块区域,未初始化的全局变量与静态变量在相邻的另一块区域,同时未被初始化的对象存储区可以通过void*来访问和操纵,程序结束后由系统自行释放。
├———————┤ 低端内存区域
│ …… │
├———————┤
│ 动态数据区 │ **堆栈区域**
├———————┤
│ …… │
├———————┤
│ 代码区 │
├———————┤
│ 静态数据区 │
├———————┤
│ …… │
├———————┤ 高端内存区域
[参考文档](https://blog.csdn.net/myqq1418/article/details/81584761)