在C++中,我们经常需要处理数据的存储问题。有时候,我们可能不知道需要多少内存,或者需要根据程序运行时的情况来动态调整内存大小。这时候,静态内存分配(比如直接定义变量)就不够用了,这就需要用到动态内存分配。
为什么需要动态内存分配?¶
我们平时写代码时,静态内存分配(比如 int a; 或 char s[20];)是在编译时就确定了内存大小,由编译器自动管理。但如果遇到这样的场景:需要存储一组不确定数量的数据(比如用户输入的多个数字),或者临时需要一块很大的内存,静态内存就显得不够灵活了。
动态内存分配允许我们在运行时根据实际需求向“堆”申请内存,使用完后再手动释放。堆是一块独立的内存区域,大小相对灵活,但需要我们自己负责管理,避免内存泄漏。
动态内存与堆/栈的简单区别¶
- 栈(Stack):由编译器自动分配和释放,用于存储局部变量、函数参数等,内存大小有限且速度快。
- 堆(Heap):程序运行时动态申请的内存区域,大小灵活但由程序员手动管理,需要显式释放。
new 和 delete 就是用来操作堆内存的核心工具。
new 操作符:在堆上分配内存¶
要在堆上申请内存,我们使用 new 操作符。它的语法很简单:
1. 分配单个对象¶
类型* 指针变量 = new 类型; // 分配一个该类型的内存空间
例如,分配一个 int 类型的动态变量:
int* p = new int; // p 指向堆上一个 int 类型的内存空间
此时,p 是一个指针,我们可以通过 *p 访问或修改这块内存的值:
*p = 100; // 将 100 存入 p 指向的内存
cout << "动态变量的值:" << *p << endl; // 输出 100
如果需要在分配时初始化内存,可以直接在 new 后加括号传入初始值:
int* num = new int(20); // 直接初始化为 20
cout << "初始化后的变量:" << *num << endl; // 输出 20
2. 分配数组¶
如果需要一组数据(比如数组),可以用 new[] 来分配:
类型* 数组指针 = new 类型[数组大小]; // 分配数组内存
例如,分配一个包含 5 个 int 的动态数组:
int* arr = new int[5]; // arr 指向一个有 5 个 int 的数组
数组元素默认不初始化(值可能是随机的),如果需要初始化(比如全为 0),可以写成:
int* arr = new int[5](); // 每个元素被初始化为 0
使用数组时,可以通过下标访问元素:
for (int i = 0; i < 5; ++i) {
arr[i] = i * 2; // 数组赋值:0, 2, 4, 6, 8
}
// 打印数组元素
for (int i = 0; i < 5; ++i) {
cout << "arr[" << i << "] = " << arr[i] << endl;
}
delete 操作符:释放堆内存¶
new 分配的内存不会自动释放,必须用 delete 或 delete[] 手动释放,否则会导致内存泄漏(程序占用的内存越来越多,最终崩溃)。
1. 释放单个对象¶
如果用 new 分配了单个对象,用 delete 释放:
int* p = new int(100);
// 使用完后释放内存
delete p; // p 指向的堆内存被释放,之后不能再用 *p
2. 释放数组¶
如果用 new[] 分配了数组,必须用 delete[] 释放,否则只会释放数组第一个元素的内存,导致内存泄漏:
int* arr = new int[5];
// 使用完后释放数组
delete[] arr; // 必须用 delete[],不能用 delete!
常见错误与注意事项¶
- 忘记释放内存:用
new分配后不delete,会导致内存泄漏。例如:
int* p = new int(5);
// 使用 p...
// 忘记写 delete p; 这里内存会一直占用
- 数组用
delete而非delete[]:例如:
int* arr = new int[10];
delete arr; // 错误!应该用 delete[] arr;
这样只会释放数组第一个元素的内存,剩下的 9 个元素内存永远不会被释放。
- 重复释放内存:同一个指针不能
delete两次,否则会导致程序崩溃:
int* p = new int;
delete p;
delete p; // 错误!重复释放,未定义行为
总结¶
动态内存分配让我们可以在运行时灵活管理内存,核心工具是 new 和 delete:
- new 用于在堆上分配单个对象或数组内存,语法分别为 new 类型 和 new 类型[大小];
- delete 用于释放单个对象的内存,delete[] 用于释放数组的内存;
- 务必用对应方式释放内存(单个对象用 delete,数组用 delete[]),避免内存泄漏或程序崩溃。
合理使用动态内存,可以让程序更高效地利用内存资源,但要时刻注意内存的分配与释放,养成良好的编程习惯。