目录
[全局/静态存储区(Global/Static Storage)](#全局/静态存储区(Global/Static Storage))
[常量存储区(Constant Storage)](#常量存储区(Constant Storage))
[代码区(Code Area)](#代码区(Code Area))
程序运行前
在程序编译后,生成了exe可执行程序,未执行该程序前分为两个区域
代码区
存放 CPU 执行的机器指令
代码区是共享的,共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可
代码区是只读的,使其只读的原因是防止程序意外地修改了它的指令
全局区
全局变量和静态变量存放在此.
全局区还包含了常量区 , 字符串常量 和其他常量也存放在此.
该区域的数据在程序结束后由操作系统释放
- C++中在程序运行前分为全局区和代码区
- 代码区特点是共享和只读
- 全局区中存放全局变量、静态变量、常量
- 常量区中存放 const修饰的全局常量 和 字符串常量
cpp
#include <iostream>
using namespace std;
//全局变量
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;
//静态变量
static int s_a = 10;
static int s_b = 10;
return 0;
}
程序运行后
不要返回局部变量的地址,栈区开辟的数据由编译器自动释放
cpp
#include <iostream>
using namespace std;
int * func(int a) // 形参也是放在栈区
{
int a = 10;
return &a; // 不要返回局部变量的地址,栈区开辟的数据由编译器自动释放
}
int main() {
int *p = func();
cout << *p << endl; // 10 第一次可以打印这个数字,是因为编译器做了保留
cout << *p << endl; // 随机值 第二次这个数据就不再保留了
return 0;
}
new
利用new关键字,可以将数据开辟到堆区
在堆区开辟数据
int *p = new int(10)
new int(10)表示在堆内存上动态分配了一个int类型的空间,并用值10初始化了该空间。
p指针变量,本质上也是局部变量,放在栈上,指针指向的是所开辟的堆内存区的数据的地址。
int *p = func()
p虽然是在func()函数中声明的局部变量,但它存储的是一个指向堆内存的地址。
当函数func()执行完毕后,p虽然在函数栈帧中被销毁,但指向堆内存的地址仍然存在。
cpp
int * func() {
/*
利用new关键字,可以将数据开辟到堆区
*/
int *p = new int(10); // new当前返回的是int类型的指针,具体什么类型由开辟的数据类型决定
return p; // 客观上返回的是堆区的地址
}
int *p = func()
/*
p虽然是在func()函数中声明的局部变量,但它存储的是一个指向堆内存的地址。
当函数func()执行完毕后,p虽然在函数栈帧中被销毁,但指向堆内存的地址仍然存在。
*/
cout << *p << endl; // 10
delete释放堆区数据
cpp
int * func() {
int *p = new int(10);
return p;
}
int *p = func();
delete p; // 释放堆区数据
cout << *p << endl; // error 内存已经释放,再次访问已经是非法操作,报错
堆区开辟数组
在堆区开辟数组------创建10个整形数据的数组
- new int[10]动态分配一个包含10个int类型元素的数组时,内存管理系统会分配一块连续的内存空间来存储这个数组。
- 指针arr存储的就是这块内存空间的起始地址,也就是数组的第一个元素的地址。
- 类似于C语言中的数组名
cpp
void test() {
/*
new int[10]动态分配一个包含10个int类型元素的数组时,内存管理系统会分配一块连续的内存空间来存储这个数组。
指针arr存储的就是这块内存空间的起始地址,也就是数组的第一个元素的地址。
类似于C语言中的数组名
*/
int *arr = new int[10]; // 10代表数组有10个元素,注意这里是中括号,不是小括号
for (int i = 0; i < 10; i++)
{
arr[i] = i + 100; // 给这10个元素赋值 1000~109 (arr[i] == *(arr + i))
}
for (int i = 0; i < 10; i++)
{
cout << arr[i] << endl; // 100 ~ 109
}
//释放堆区的数组数据内存。数组需要加 []
delete[] arr;
}
test();
内存分区模型
C++的内存分区模型描述了程序在运行时如何使用系统内存。了解内存分区模型对于理解程序的内存管理和运行效率非常重要!
在一般情况下,C++程序在内存中的布局可以分为以下几个主要区域:
栈(Stack)
- 栈是用于存储局部变量、函数参数、函数返回地址以及函数调用时所需的临时数据的区域。
- 栈的大小在程序运行时是可以动态变化的,通常由系统自动管理。
- 栈内存的分配和释放是由系统自动完成的,遵循"先进后出"的原则。
堆(Heap)
- 堆被用于存储动态分配的内存,例如使用
new
和delete
关键字来分配和释放的内存。 - 堆的大小也是动态变化的,可以在程序运行时根据需要进行分配和释放。
- 程序员通常需要手动管理堆内存的分配和释放,因此在使用时需要注意内存泄漏和内存溢出的风险。
全局/静态存储区(Global/Static Storage)
- 全局变量、静态变量以及常量通常存储在这个区域。
- 这部分内存在程序启动时就被分配,并在程序结束时才被释放,它们的生命周期与整个程序的生命周期相同。
常量存储区(Constant Storage)
- 存放常量数据,如字符串常量等。
- 这部分内存通常被固定分配,并且存储的数据在程序运行期间不会改变。
代码区(Code Area)
- 存放程序的执行代码,通常是只读的。
- 程序的机器指令和函数体都存储在这个区域。