程序的内存模型——四区
代码区
代码区(程序运行前):存放什么?——代码存放函数体的二进制代码,由操作系统进行管理。
将写的代码转换成二进制数据存储在代码区中,以便重复使用。
代码区特点:共享和只读。
代码区是共享的,共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可。
代码区是只读的,使其只读原因是防止程序意外地修改了它的指令。
全局区
全局区(程序运行前):存放什么?
存放全局变量和静态变量以及常量。
全局变量:在main函数之外定义的变量。
静态变量:无论是否在main函数中定义的变量,前面加上static
关键字修饰,都是静态变量。静态变量有什么特点?课程中没说,以下是Google得到结果。
常量:常量分为字符串常量和const修饰的变量。而const修饰的变量又分为const全局变量和const局部变量。只有const全局变量才会放在全局区,const局部变量会放在。
如何通过实验明显地观察出来?
实验思路为:分别设置几种变量:①全局变量;②静态变量—main函数中 | 外;③字符串常量;④const局部变量;⑤const全局变量。分别打印它们的地址。可以发现,局部变量(main函数中以及main函数中const修饰的变量)它们的地址是紧挨着的。而对于全局变量、静态变量、const全局变量,它们的地址是紧挨着。
通过该实验,就能明白,哪些变量|常量在一块,哪些是分开的。
以下是实验代码。
#include<iostream>
#include<string>
#include"print.h"
using namespace std;
//全局变量
int global_a = 10;
int global_b = 20;
//全局static变量
static int global_static_a = 10;
static int global_static_b = 20;
//全局const变量
const int global_const_a = 10;
const int global_const_b = 20;
int main() {
//局部变量
int local_a = 10;
int local_b = 20;
//局部static变量
static int local_static_a = 10;
static int local_static_b = 20;
//局部const变量
const int local_const_a = 10;
const int local_const_b = 20;
//常量
//cout << "变量名称" << "\t\t" << "局部" << "\t\t" <<"\t\t" << "全局" << "\t\t" <<"\t\t" << endl;
cout << "类型" << "\t\t\ta\t\t\tb" << endl;
cout << "全局" << endl;
cout << "全局变量" << "\t\t"<<(int)&global_a<<"\t\t"<<(int)&global_b<<endl;
cout << "全局static变量" << "\t\t"<<(int)&global_static_a<<"\t\t"<<(int)&global_static_b<<endl;
cout << "全局const变量" << "\t\t"<<(int)&global_const_a<<"\t\t"<<(int)&global_const_b<<endl;
cout << "局部" << endl;
cout << "局部变量" << "\t\t"<<(int)&local_a<<"\t\t"<<(int)&local_b<<endl;
cout << "局部static变量" << "\t\t"<<(int)&local_static_a<<"\t\t"<<(int)&local_static_b <<endl;
cout << "局部const变量" << "\t\t"<<(int)&local_const_a <<"\t\t"<<(int)&local_const_b<<endl;
cout << "常量" << endl;
cout << "常量" << "\t\t"<<(int)&"常量" << "\t\t"<<endl;
system("pause");
}
实验打印输出
通过观察,可以验证:
①无论static变量是否在全局还是在局部,它们都在全局区保存,因为都是941158
开头的内存区。
②在全局区的变量类型有:全局变量,全局const变量,static变量,常量。
③const修饰局部变量,没有存放在全局区。const修饰全局变量,在全局区。
栈区
栈区(程序运行后):存放什么?
由编译器自动分配释放,存放函数的参数值,局部变量等。
注意,不要返回在栈区的数据指针。为什么?因为编译器会保留一次,保留的这次可以读取,可以打印输出。但也仅保留一次,之后再读取,打印输出就是乱码。
实验验证:思路:返回函数数据指针,并打印值。
代码:
#include<iostream>
#include<string>
using namespace std;
int* StackFunc2() {
int a = 10;
cout << "a的地址为:" << &a << endl;
cout << "a的十进制地址为:" << (int) & a << endl;
return &a;
}
int main() {
//MemoryOfGlobal(&global_a, &global_b, &global_static_a, &global_static_b, &global_const_a, &global_const_b);
int* ptr = StackFunc2();
cout << "保留的这次为:" << *ptr << endl;
cout << "第二次打印输出为:" << *ptr << endl;
cout << "第三次打印输出为:" << *ptr << endl;
system("pause");
}
实验结果:
一次都没有保存。说明若返回局部变量值会出现问题——乱码。
若返回局部static
变量呢?做法:修改a为static int
。
可以打印输出。
堆区
堆区(程序运行后):存放什么?存放
由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收。
由程序员自己索取的内存空间,若程序员没有自己释放,则在程序结束后由编译器自动释放。
如何自己创建内存空间?使用new
关键词。new关键字返回的是内存的地址,所以要用指针数据类型接收它。
案例代码:
#include<iostream>
#include<string>
using namespace std;
int* UseNew() {
int* a = new int(10);
return a;
}
int main() {
int* new_ptr = UseNew();
cout << "使用新开辟的内存空间的值为:" << *new_ptr << endl;
system("pause");
}
实验结束:
四区存在意义:不同区域存放的数据,赋予不同的生命周期,灵活编程。