💗个人主页💗
⭐个人专栏------C++学习⭐
💫点击关注🤩一起学习C语言💯💫
目录
[1. C/C++内存分布](#1. C/C++内存分布)
[2. C语言中动态内存管理方式](#2. C语言中动态内存管理方式)
[3. C++内存管理方式](#3. C++内存管理方式)
[3.1 new/delete操作内置类型](#3.1 new/delete操作内置类型)
[3.2 new和delete操作自定义类型](#3.2 new和delete操作自定义类型)
[4. operator new与operator delete函数](#4. operator new与operator delete函数)
1. C/C++内存分布
C/C++程序的内存分布主要分为以下几个部分:
-
栈(Stack):栈是用来存储局部变量、函数参数等的内存区域。每当一个函数被调用时,都会分配一块栈帧来存储函数的局部变量和参数。栈是按照"先进后出"的原则进行管理,函数返回后,其所占用的栈帧会被释放。
-
堆(Heap):堆是用来动态分配内存的区域。在C/C++中,使用new/delete或malloc/free来进行堆内存的动态分配与释放。堆是按照"先进先出"的原则进行管理,需要手动释放分配的内存。
-
全局/静态存储区(Global/Static Storage):全局变量和静态变量都存储在这个区域中。全局变量在程序运行期间一直存在,静态变量的生命周期是整个程序运行期间。
-
常量存储区(Constant Storage):存储常量数据,例如字符串常量。这个区域的数据在程序运行期间不能被修改。
-
代码区(Code/Text):存储程序的机器指令。代码区是只读的,程序在运行时不能修改代码区的内容。
2. C语言中动态内存管理方式
在C语言中,动态内存管理主要通过以下几个函数来实现:
-
malloc():用于分配指定大小的字节内存块。它接受一个参数,即所需内存的字节数,并返回一个指向分配内存的指针。
-
calloc():用于分配指定数量和大小的连续内存块,并将每个字节都初始化为零。它接受两个参数,即所需内存块的数量和每个内存块的字节数,并返回一个指向分配内存的指针。
-
realloc():用于重新分配已分配内存块的大小。它接受两个参数,即指向要重新分配大小的内存块的指针和新的内存块大小,并返回一个指向重新分配内存的指针。
-
free():用于释放之前通过malloc()或calloc()分配的内存块。它接受一个参数,即要释放的内存块的指针。
cpp
#include <stdio.h>
#include <stdlib.h>
int main() {
int* numbers;
// 分配存储5个整数的内存块
numbers = (int*)malloc(5 * sizeof(int));
if (numbers == NULL) {
printf("内存分配失败\n");
return 1;
}
// 向每个元素赋值
for (int i = 0; i < 5; i++) {
numbers[i] = i + 1;
}
// 打印每个元素的值
for (int i = 0; i < 5; i++) {
printf("%d ", numbers[i]);
}
printf("\n");
// 重新分配内存块的大小为10个整数
numbers = (int*)realloc(numbers, 10 * sizeof(int));
if (numbers == NULL) {
printf("内存重新分配失败\n");
return 1;
}
// 向新增的元素赋值
for (int i = 5; i < 10; i++) {
numbers[i] = i + 1;
}
// 打印每个元素的值
for (int i = 0; i < 10; i++) {
printf("%d ", numbers[i]);
}
printf("\n");
// 释放内存块
free(numbers);
return 0;
}
3. C++内存管理方式
C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因 此C++又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理。
-
new/delete运算符:new运算符用于动态分配单个对象的内存,并返回指向该对象的指针,而delete运算符用于释放通过new分配的内存。相较于malloc/free函数,new和delete可以自动调用对象的构造函数和析构函数。
-
new[]/delete[]运算符:new[]运算符用于动态分配对象数组的内存,并返回指向该数组的指针,而delete[]运算符用于释放通过new[]分配的内存。相较于malloc/free函数,new[]和delete[]可以自动调用每个对象的构造函数和析构函数。
3.1 new/delete操作内置类型
- new操作符:使用new操作符可以动态分配内置类型的内存空间,并返回指向该内存空间的指针。
cpp
int* p = new int; // 动态分配一个int类型的内存空间
float* q = new float; // 动态分配一个float类型的内存空间
- delete操作符:使用delete操作符可以释放通过new操作符分配的内存空间,同时调用内置类型的析构函数进行资源的清理。
cpp
delete p; // 释放之前分配的int类型的内存空间
delete q; // 释放之前分配的float类型的内存空间
需要注意的是,对于内置类型,因为它们没有构造函数和析构函数,所以delete操作符只会释放内存空间,并不会进行其他操作。
而且,使用delete操作符释放的内存空间必须是通过new操作符进行分配的,否则可能导致未定义的行为。另外,动态分配的内置类型的内存空间一旦不再需要,应当及时释放,以避免内存泄漏和资源的浪费。
cpp
void Test()
{
// 动态申请一个int类型的空间
int* ptr4 = new int;
// 动态申请一个int类型的空间并初始化为10
int* ptr5 = new int(10);
// 动态申请10个int类型的空间
int* ptr6 = new int[3];
delete ptr4;
delete ptr5;
delete[] ptr6;
}
3.2 new和delete操作自定义类型
cpp
class MyClass
{
public:
int* data;
MyClass()
{
data = new int[5]; // 动态分配一个包含5个int元素的数组
cout << "Constructor called" << endl;
}
~MyClass()
{
delete[] data; // 释放之前分配的数组内存空间
cout << "Destructor called" << endl;
}
};
int main()
{
MyClass* obj = new MyClass(); // 动态分配一个MyClass对象的内存空间,并进行初始化
// 使用动态分配的内存空间
for (int i = 0; i < 5; i++)
{
obj->data[i] = i;
cout << obj->data[i] << " ";
}
cout << endl;
delete obj; // 释放之前分配的MyClass对象的内存空间,并调用析构函数
return 0;
}
4. operator new与operator delete函数
operator new和operator delete是C++中的全局函数,用于自定义类对象的动态内存管理。new在底层调用operator new全局函数来申请空间,delete在底层通过 operator delete全局函数来释放空间。
注意: operator new和operator delete不是对new和delete的重载,这是俩库函数
operator new函数用于分配内存空间:
cpp
void* operator new (std::size_t size);
它接受一个参数size,表示要分配的内存空间的大小,返回一个void指针,指向已分配的内存空间的起始地址。
operator delete函数用于释放内存空间:
cpp
void operator delete (void* ptr);
它接受一个参数ptr,表示要释放的内存空间的起始地址,无返回值。
这两个函数可以被重载,用于自定义内存分配和释放的行为。
cpp
class MyClass
{
public:
int data;
MyClass(int d) : data(d)
{
std::cout << "Constructor called" << std::endl;
}
~MyClass()
{
std::cout << "Destructor called" << std::endl;
}
static void* operator new (size_t size)
{
std::cout << "Custom new operator called" << std::endl;
void* ptr = std::malloc(size); // 使用malloc来分配内存空间
if (!ptr)
{
throw std::bad_alloc(); // 内存分配失败,抛出异常
}
return ptr;
}
static void operator delete (void* ptr)
{
std::cout << "Custom delete operator called" << std::endl;
std::free(ptr); // 使用free来释放内存空间
}
};
int main()
{
MyClass* obj = new MyClass(10);
delete obj;
return 0;
}