1 内存分区模型
C++程序在执行时,将内存大方向划分为4个区域
- 代码区;存放函数体的二进制代码,由操作系统进行管理;
- 全局区;存放全局变量和静态变量以及常量;
- 栈区;由编译器自动分配内存,存放函数的参数值,局部变量等;
- 堆区;由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收。
内存分区的意义:
不同区域存放的数据,赋予不同的生命周期,给我们更大的空间和灵活度编程。
1.1 程序运行前
在程序编译后,生成了exe可执行程序,未执行该程序前分为两个区域:
代码区:
存放CPU执行的机器质量
代码区是共享的,共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可
代码区是只读的,使其只读的原因是防止程序意外地修改了它的指令
全局区:
全局变量和静态变量存放在此
全局区还包含了常量区,字符串常类和其它常量也存放在此
该区域的数据在程序结束后由操作系统释放
/*
定义在外部的变量是全局变量
局部变量只在其函数内生效,外部引用需重新定义
*/
int b = 5;
//这是const修饰的全局变量,全局常量
const int e = 2;
int main() {
//这种定义在函数里面的就是局部变量
int a = 10;
//分别打印全局变量和局部变量的地址,发现其存储地址不在一个区间
//需要注意的是,全局变量定义之后,其地址不会变动
cout << "a的内存地址:" << int(&a) << endl;
cout << "b的内存地址:" << int(&b) << endl;
//全局区不仅存放全局变量,还有静态变量,常量
//在变量前加上staitc则为静态变量
//可以看到,静态变量和全局变量的存放地址是在一个区间的
static int c = 15;
cout << "c的内存地址:" << int(&c) << endl;
//常量,有字符串常量和const修饰常量之分;其内存地址与全局变量相近
//字符串常量
cout << "字符串常量的内存地址:" << int(&"hello world") << endl;
cout << "const全局常量的内存地址:" << int(&e) << endl;
//const修饰的变量,又分为修饰全局变量和修饰局部变量
//修饰全局变量
const int f = 10;
cout << "const全局常量的内存地址:" << int(&e) << endl;
//局部变量
//存放地址与局部变量相近
const int f = 10;
cout << "const局部常量的内存地址:" << int(&f) << endl;
}
1.2 程序运行后
栈区:
栈区数据由编译器自动分配和释放,存放函数的参数值,局部变量等
注意事项:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放
示例:
//返回一个int类型的指针
int* func(int b) {
b = 100; //形参数据也存放在栈区
int a = 10; //局部变量,存放在栈区,栈区的数据在函数执行完后自动释放
return &a; //返回局部变量的地址(释放后再使用属于非法操作)
}
int main() {
int * p = func();
cout << *p << endl; //第一次可以打印,编译器做了一次保留
cout << *p << endl; //乱码,数据不再保留
system("pause");
return 0;
}
堆区:
由程序员分配释放,若程序员不释放,程序结束时由操作系统回收
在C++中主要利用new在堆区开辟内存
示例:
int* func() {
//利用new关键字将数据开辟到堆区
//括号内为定义的值,返回值为所创建内存地址,用指针存放
//指针本质也是局部变量,放在栈区,指针保持的数据是放在堆区
int * p = new int(10);
return p