总览
主要讲了 c++ 中程序的内存模型的四个区域:代码区、全局区、栈区、堆区以及 new 关键字的使用
内存分区模型
c++ 程序在执行时,内存大致可以分为以下四个区域:
- 代码区:存放函数体的二进制代码,由操作系统进行管理
- 全局区:存放全局变量、静态变量以及常量
- 栈区:由编译器自动分配释放,存放函数的参数值、局部变量等
- 堆区:由程序员分配和释放,若程序员不释放,则程序结束时由操作系统回收
分区意义:分区方便管理,每一部分的生命周期不同,而且每一部分的申请释放权限可能也不同
代码区
程序编译后,生成可执行程序(不同操作系统的后缀不同),在程序未执行前只存在两个区域:代码区以及全局区
功能:存放 cpu 执行的机器指令
代码区是共享的,共享的目的是对于被频繁执行的程序,只需要在内存中有一份代码即可
代码区是只读的,防止程序意外地修改了它的指令
全局区
功能:存放全局变量和静态变量,同时还包含了常量区,字符串常量和其他常量也存放在此
此区域的数据在程序结束后由操作系统进行释放
#include <iostream>
using namespace std;
#define MAX 1000
// 2. 全局变量
int global_a = 10;
int global_b = 20;
// 5. 常量 - const修饰的全局变量
constexpr int const_global_a = 10;
constexpr int const_global_b = 20;
int main() {
// 全局区:存放全局变量、静态变量以及常量
//1. 普通局部变量
int a = 10;
int b = 20;
// 0x16d9c6fe8 0x16d9c6fe4
cout << &a << " " << &b << endl;
// 2. 0x102440000 0x102440004
cout << &global_a << " " << &global_b << endl;
// 3. 静态变量
static int s_a = 10;
static int s_b = 20;
// 0x102440008 0x10244000c
cout << &s_a << " " << &s_b << endl;
//4. 常量 - 字符串常量
// 0x100905b4a 0x100905b50
cout << &"hello" << " " << &"world" << endl;
// 5. 0x100cc1c18 0x100cc1c1c
cout << &const_global_a << " " << &const_global_b << endl;
// 6. 常量 - const修饰的局部变量
const int const_a = 10;
const int const_b = 20;
// 0x16f13efe0 0x16f13efdc
cout << &const_a << " " << &const_b << endl;
return 0;
}
由上面代码及图可得,全局区包含情况如下:
- 普通局部变量❌
- 全局变量 ✅
- 静态变量 ✅
- 常量-字符串常量 ✅
- 全局常量(const修饰全局变量)✅
- 局部常量(const修饰局部变量)❌
栈区
功能:存放函数的参数值、局部变量等,由编译器自动分配释放
#include <iostream>
using namespace std;
#define MAX 1000
//栈区的数据由编译器管理开辟和释放
int* solve() {
int a = 10;
return &a;
}
int main() {
int * p = solve();
// 10,这次可以打印正确的,是因为编译器做了一次保留
cout << *p << endl;
// 1,第二次这个数据就被释放了
cout << *p << endl;
return 0;
}
由代码总结,不要返回函数内局部变量的地址,因为返回后编译器就会做回收,指针就失效了
堆区
- 由程序员分配释放;若程序员没有释放,程序结束时由操作系统进行释放
- 在 c++ 中主要利用 new 在堆中开辟空间
#include <iostream>
using namespace std;
#define MAX 1000
int* solve() {
// 利用 new 关键字,可以将数据开辟到堆区
int * p = new int(10);
return p;
}
int main() {
int * p = solve();
// 10
cout << *p << endl;
// 10
cout << *p << endl;
free(p); // 记得释放内存,不然会提示leak
return 0;
}
new 操作符
- c++ 利用 new 来在堆上开辟空间
- 语法: new 数据类型(值);
- 堆区的数据由程序员手动开辟,释放时使用 delete 操作符
- 利用 new 创建的数据,会返回该数据对应类型的指针
#include <iostream>
using namespace std;
#define MAX 1000
int * getNum() {
// new关键字用法,返回的是这个数据类型的指针
int * p = new int(10);
return p;
}
void test() {
int * p = getNum();
// 10
cout << *p << endl;
delete p;
// -491814896 内存空间已被释放
cout << *p << endl;
}
// 利用 new 开辟数组
void getArr() {
int * arr = new int[10];
// 赋值
for (int i = 0; i < 10; i++) {
arr[i] = i;
}
// 打印
for (int i = 0; i < 10; i++) {
cout << arr[i] << endl;
}
// 释放数组的时候,需要使用 delete[]
delete[] arr;
}
int main() {
test();
getArr();
return 0;
}