这里写目录标题
C语言中动态内存管理
C语言中动态内存管理方式:malloc/calloc/realloc/free
| 特性 | malloc | calloc | realloc |
|---|---|---|---|
| 核心功能 | 基础分配 | 分配并初始化为 0 | 调整已分配内存的大小 |
| 函数参数 | 1个(总字节数) | 2个(元素个数, 单个元素大小) | 2个(原内存指针, 新字节数) |
| 内存初始化 | 不初始化,内存里是随机的垃圾值 | 自动清零,所有位初始化为 0 | 保留原有数据,新扩容部分不初始化 |
| 典型用途 | 追求高性能,或后续会立刻赋值的场景 | 分配数组、结构体,或需要"干净"内存的场景 | 动态数组扩容、缩容 |
当然,realloc的开辟方法有点特殊
情况一:原地扩容(运气好)
情况二:异地搬迁(你说的"新找一个空间")
void Test ()
{
// 1.malloc/calloc/realloc的区别是什么?
int* p2 = (int*)calloc(4, sizeof (int));
int* p3 = (int*)realloc(p2, sizeof(int)*10);
// 这里需要free(p2)吗?
free(p3 );
}
注:不需要free掉p2了,因为realloc在调用的时候就已经把p2给释放掉了
代码
javascript
#include <stdio.h>
#include <stdlib.h>
int main() {
int *arr = NULL;
// ==========================================
// 1. malloc:只分配空间,不初始化(里面是随机的垃圾值)
// ==========================================
printf("--- 1. 测试 malloc ---\n");
// 申请 5 个 int 的空间
arr = (int*)malloc(5 * sizeof(int));
if (arr == NULL) return 1; // 必须检查内存是否分配成功
printf("malloc 申请 5 个空间后的初始值(通常是乱码/垃圾值):\n");
for (int i = 0; i < 5; i++) {
printf("%d ", arr[i]);
}
printf("\n\n");
// 用完记得释放,方便后面演示 calloc
free(arr);
arr = NULL;
// ==========================================
// 2. calloc:分配空间,并自动将所有位初始化为 0
// ==========================================
printf("--- 2. 测试 calloc ---\n");
// 申请 5 个 int 的空间,参数是 (元素个数, 单个元素大小)
arr = (int*)calloc(5, sizeof(int));
if (arr == NULL) return 1;
printf("calloc 申请 5 个空间后的初始值(自动清零):\n");
for (int i = 0; i < 5; i++) {
printf("%d ", arr[i]);
}
printf("\n\n");
// ==========================================
// 3. realloc:调整已分配内存的大小(扩容/缩容)
// ==========================================
printf("--- 3. 测试 realloc ---\n");
// 现在想把数组从 5 个 int 扩容到 10 个 int
// 注意:必须用临时指针接收 realloc 的返回值,防止失败导致原指针丢失
int *temp = (int*)realloc(arr, 10 * sizeof(int));
if (temp == NULL) {
free(arr); // 扩容失败也要释放原来的内存
return 1;
}
arr = temp; // 扩容成功,更新指针
printf("realloc 扩容到 10 个空间后的值:\n");
printf("前 5 个是原来 calloc 留下的 0,后 5 个是新增的(通常是垃圾值):\n");
for (int i = 0; i < 10; i++) {
printf("%d ", arr[i]);
}
printf("\n");
// ==========================================
// 程序结束,统一释放内存
// ==========================================
free(arr);
arr = NULL;
return 0;
}
C++内存管理方式
通过new和delete操作符进行动态内存管理。
代码
javascript
void Test()
{
// 动态申请一个int类型的空间
int* ptr4 = new int;
// 动态申请一个int类型的空间并初始化为10
int* ptr5 = new int(10);
// 动态申请3个int类型的空间
int* ptr6 = new int[3];
int* ptr10 = new int[10]{1, 2, 3}; // 申请 10 个 int 的数组并初始化
delete ptr4;
delete ptr5;
delete[] ptr6;
delete[] ptr10;
}
单个对象:用 new 申请,必须用 delete 释放。
连续空间(数组):用 new[] 申请,必须用 delete[] 释放。
核心原则:申请时用了方括号 [],释放时就必须带上 [];申请时没带,释放时也不能带。
两者区别
在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc与free不会。
代码体现
javascript
#include <iostream>
#include <cstdlib> // malloc 和 free 需要的头文件
using namespace std;
class Student {
public:
// 构造函数
Student(int id = 0) : _id(id) {
cout << "【构造函数】被调用!学生ID: " << _id << endl;
}
// 析构函数
~Student() {
cout << "【析构函数】被调用!学生ID: " << _id << " 正在释放资源..." << endl;
}
private:
int _id;
};
int main() {
cout << "------ 1. 测试 malloc 和 free (C语言风格) ------" << endl;
// malloc 只管开辟空间,不会调用构造函数
Student* s1 = (Student*)malloc(sizeof(Student));
cout << "malloc 开辟空间完毕(注意:上面没有打印构造函数)\n" << endl;
// free 只管释放空间,不会调用析构函数
free(s1);
cout << "free 释放空间完毕(注意:上面也没有打印析构函数)\n\n" << endl;
cout << "------ 2. 测试 new 和 delete (C++风格) ------" << endl;
// new 开辟空间的同时,会自动调用构造函数
Student* s2 = new Student(1001);
cout << "new 开辟空间完毕(注意:上面自动打印了构造函数)\n" << endl;
// delete 释放空间前,会自动调用析构函数
delete s2;
cout << "delete 释放空间完毕(注意:上面自动打印了析构函数)" << endl;
return 0;
}
new
new干了两件事
1.开辟对象的空间
2.调用构造函数
delete
delete干了两件事
1.先调用析构函数
2.把p1指向的空间释放