C++程序在执行时,将内存大方向划分为4个区域
代码区:存放函数体的二进制代码,所有代码都会放入这个区,由操作系统进行管理的
全局区:存放全局变量和静态变量以及常量
栈区:由编译器自动分配释放, 存放函数的参数值,局部变量等
堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收
内存四区意义:
不同区域存放的数据,赋予不同的生命周期, 给我们更大的灵活编程
一、程序运行前
为什么需要这两个特点?
-
只读:避免程序运行时动态修改指令导致不可预测行为(如病毒注入)、提高稳定性,确保代码逻辑的一致性。
-
共享:减少重复代码的内存占用(尤其对系统级程序如
libc
库)、提升多进程环境的效率(如 Web 服务器启动多个 worker 进程)。
//全局变量
int g_a = 10;
int g_b = 10;
//全局常量
const int c_g_a = 10;
const int c_g_b = 10;
int main() {
//局部变量
int a = 10;
int b = 10;
//打印地址
cout << "局部变量a地址为: " << (int)&a << endl;
cout << "局部变量b地址为: " << (int)&b << endl;
cout << "全局变量g_a地址为: " << (int)&g_a << endl;
cout << "全局变量g_b地址为: " << (int)&g_b << endl;
//静态变量
static int s_a = 10;
static int s_b = 10;
cout << "静态变量s_a地址为: " << (int)&s_a << endl;
cout << "静态变量s_b地址为: " << (int)&s_b << endl;
//字符串常量
cout << "字符串常量地址为: " << (int)&"hello world" << endl;
cout << "字符串常量地址为: " << (int)&"hello world1" << endl;
cout << "全局常量c_g_a地址为: " << (int)&c_g_a << endl;
cout << "全局常量c_g_b地址为: " << (int)&c_g_b << endl;
const int c_l_a = 10;
const int c_l_b = 10;
cout << "局部常量c_l_a地址为: " << (int)&c_l_a << endl;
cout << "局部常量c_l_b地址为: " << (int)&c_l_b << endl;
system("pause");
return 0;
}
总结:
全局区(数据区)中存放: 全局变量、静态变量
常量区中存放: const修饰的全局变量(全局常量)、字符串常量。(只读区)
存放在栈区:const修饰的局部变量(局部常量)、局部变量。
高地址 | |
栈区 (Stack) | ← 局部变量、局部常量(如 `int x`, `const int y`) 地址:0x7ffd... → 0x7ffc...(向低增长) |
堆区 (Heap) | ← `malloc`/`new` 动态分配(地址无固定规律) |
数据区 (Data/BSS) | ← 全局变量、静态变量(如 `g_var`, `s_local`) 地址:0x601044... |
只读数据区 (RO Data) | ← 字符串常量、全局常量(如 `"Hello"`, `G_CONST`) |
代码区 (Text) | 程序指令(如 `main()` 的机器码) 地址:0x400000... |
底地址 |
二、程序运行后
栈区:
由编译器自动分配释放, 存放函数的参数值,局部变量、形参等
注意事项:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放
示例:
int * func()
{
int a = 10;
return &a;
}
int main() {
int *p = func();
cout << *p << endl;//第一次可以正确打印是因为编译器帮忙给数据做了一次保留
cout << *p << endl;//第二次出现乱码,编译器已经释放数据
system("pause");
return 0;
}
堆区:
由程序员分配释放,若程序员不释放,程序结束时由操作系统回收
在C++中主要利用new在堆区开辟内存
示例:
int* func()
{
int* a = new int(10);
return a;
}
int main() {
int *p = func();
cout << *p << endl;
cout << *p << endl;
system("pause");
return 0;
}
C语言中的开辟动态内存方式: int * p=(int *)malloc(sizeof(int));
C++语言中的开辟动态内存方式:int * p=(int *)new int(x);
总结:
堆区数据由程序员管理开辟和释放
堆区数据利用new关键字进行开辟内存
new操作符
C++中利用new操作符在堆区开辟数据
堆区开辟的数据,由程序员手动开辟,手动释放,释放利用操作符 delete
语法: new 数据类型
利用new创建的数据,会返回该数据对应的类型的指针
示例1: 基本语法
#include <iostream>
using namespace std;
//任务一:在堆中开辟一个int数据空间
int* func_01()
{
int* p = new int(10);
return p;
}
int main()
{
int* p = func_01();
cout << *p << endl;//不管打印多少个都是显示原始数据
cout << p << endl;//显示的是原始堆地址
delete p;
cout << p << endl;//显示的是乱码,说明已经释放空间
system("pause");
return 0;
}
#include <iostream>
using namespace std;
//任务二:在堆中开辟一个int数组空间
int* func_02()
{
int* arr = new int[10];
for (int i = 0; i < 10; i++)
{
arr[i] = i + 10;
}
for (int i = 0; i < 10; i++)
{
cout << arr[i] << endl;
}
return arr;
}
int main()
{
int* arr = func_02();
delete[] arr;//释放数组要加[]
system("pause");
return 0;
}