C/C++内存管理

P. S.:以下代码均在VS2019环境下测试,不代表所有编译器均可通过。 P. S.:测试代码均未展示头文件stdio.h的声明,使用时请自行添加。

博主主页:Yan. yan.

C语言专栏

数据结构专栏

力扣牛客经典题目专栏

C++专栏

文章目录

  • [1、C / C++内存分布](#1、C / C++内存分布)
  • [2、 C语言中动态内存管理方式:malloc/calloc/realloc/free](#2、 C语言中动态内存管理方式:malloc/calloc/realloc/free)
  • 3、C++的内存管理方式
  • [4、 operator new与operator delete函数](#4、 operator new与operator delete函数)
    • [**operator new与operator delete函数(重点)**](#operator new与operator delete函数(重点))
  • [5 、new和delete的实现原理](#5 、new和delete的实现原理)
  • [6、定位new表达式(placement-new) (了解)](#6、定位new表达式(placement-new) (了解))
  • 7、总结:malloc/free和new/delete的区别

1、C / C++内存分布

先来看一段代码:

cpp 复制代码
int globalVar = 1;
static int staticGlobalVar = 1;

void Test()
{
	static int staticVar = 1;

	int localVar = 1;
	int num1[10] = { 1, 2, 3, 4 };

	char char2[] = "abcd";
	const char* pChar3 = "abcd";

	int* ptr1 = (int*)malloc(sizeof(int) * 4);
	int* ptr2 = (int*)calloc(4, sizeof(int));
	int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);

	free(ptr1);
	free(ptr3);
}
  1. 选择题:
    选项: A.栈 B.堆 C.数据段 D.代码段
    globalVar在哪里?C staticGlobalVar在哪里?C
    staticVar在哪里?C localVar在哪里?A
    num1 在哪里?A
    char2在哪里?A *char2在哪里?A
    pChar3在哪里?A *pChar3在哪里?D
    ptr1在哪里?A *ptr1在哪里?B
  2. 填空题:
    sizeof(num1) = 40 ;
    sizeof(char2) = 5 ; strlen(char2) = 4 ;
    sizeof(pChar3) = 4/8 ; strlen(pChar3) = 4 ;
    sizeof(ptr1) = 4/8;

这里给出一张图:

C/C++程序内存分配的几个区域:

  • 又叫堆栈--非静态局部变量/函数参数/返回值等等,栈是向下增长的。
  • 内存映射段 是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口
    创建共享共享内存,做进程间通信。(Linux课程如果没学到这块,现在只需要了解一下
  • 用于程序运行时动态内存分配,堆是可以上增长的。
  • 数据段--存储全局数据和静态数据。
  • 代码段--可执行的代码/只读常量。

2、 C语言中动态内存管理方式:malloc/calloc/realloc/free

代码演示:

cpp 复制代码
void Func()
{
	int* p1 = (int*)malloc(sizeof(int));
	free(p1);

	int* p2 = (int*)calloc(4, sizeof(int));
	free(p2);

	int* p3 = (int*)realloc(p2, sizeof(int)*10);
}
  • malloc
    在内存的动态存储区中分配一块长度为size字节的连续区域,参数size为需要内存空间的长度,返回该区域的首地址。

  • calloc
    与malloc相似,但是calloc会将所分配的内存空间的每一位都初始化为0。

  • realloc
    给一个已经分配了地址的指针重新分配空间,可以做到对动态开辟内存大小的调整。

  • 【面试题】malloc/calloc/realloc的区别

  1. 函数malloc不能初始化所分配的内存空间,而函数calloc可以如果malloc函数分配的空间内存原来没有被使用过,其中的每一位可能都是0,相反,如果这部分空间被使用过,那么其中可能留有各种各样的数据,也就是说,malloc函数的程序开始时(内存空间还未被分配)可以正常运行,但运行一段时间以后(内存空间已经被分配)可能会出现问题。
  2. 函数calloc可以将所分配的内存空间的每一位都初始化为0如果是字符类型或者整数类型的元素分配类型,那么这些元素会保证被初始化为0,如果是指针类型的元素分配类型,那么这些元素会被初始化为空指针。
  3. 函数malloc向系统申请分配指定Size个字节的内存空间,返回类型是void类型,void类型表示为确定类型的指针, C/C++中规定,void*类型可以强制转换成其他任意类型的指针。
  4. realloc函数可以对给定的指针所指向的空间进行缩小或放大,无论是放大还是缩小,空间内容都不会改变,但是,在缩小的时候,被缩小的那一部分空间的内容会丢失,realloc并不保证调整后的内存空间和调整前的内存空间保持同一内存地址,realloc返回的指针可能会指向一个新的内存地址。
  5. realloc是从堆上分配内存的.当扩大一块内存空间时,realloc()试图直接从堆上现存的数据后面的那些字节中获得附加的字节,如果能够满足,此时即原地扩;如果数据后面的字节不够,那么就使用堆上第一个有足够大小的自由块,现存的数据然后就被拷贝至新的位置,而老块则放回到堆上.这句话传递的一个重要的信息就是数据可能被移动,即异地扩。

3、C++的内存管理方式

C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因此C++又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理

cpp 复制代码
void Test()
{
	// 动态申请一个int类型的空间
	int* ptr4 = new int;

	// 动态申请一个int类型的空间并初始化为10
	int* ptr5 = new int(10);

	// 动态申请10个int类型的空间
	int* ptr6 = new int[10];

	// 动态申请10个int类型的空间并初始化
	int* ptr7 = new int[10]{ 9, 8, 7, 4, 5 };

	delete ptr4;
	delete ptr5;
	delete[] ptr6;
	delete[] ptr7;
}


申请和释放单个元素的空间,使用new和delete操作符,

申请和释放连续的空间,使用new[]和delete[],

注意:匹配起来使用。

new和delete操作自定义类型

  1. 申请空间时: malloc只开空间,new既开空间又调用构造函数初始化。
  2. 释放空间时: delete会调用析构函数,free不会。

malloc和free:

malloc的对象只是开辟了空间,并没有初始化,free后也只是普通的释放。

new和delete:

使用new,既可以开辟空间,又调用了构造函数从而完成初始化,而delete时调用了析构函数,以此释放空间。

4、 operator new与operator delete函数

operator new与operator delete函数(重点)

newdelete 是用户进行动态内存申请释放 的操作符

operator newoperator delete 是系统提供的全局函数

new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间。

  • 注意:operator new和operator delete不是对new和delete的重载,这是两个库函数。

operator new :该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间失败,尝试执行空间不足应对措施,如果改应对措施用户设置了,则继续申请,否则抛异常

operator new本质是封装了malloc。operator delete本质是封装了free。

具体使用operator new和operator delete的操作如下::

cpp 复制代码
int main()
{
	int* p1 = (int*)operator new(sizeof(int));
	operator delete(p1);

	int* p2 = (int*)malloc(sizeof(int));
	if (p2 == NULL)
	{
		perror("申请失败!!");
		return;
	}
	free(p2);

	return 0;
}

operator new和operator delete的功能和malloc、free一样。也不会去调用构造函数和析构函数。不过还是有区别的:

1、operator new不需要检查开辟空间的合法性。

2、operator new开辟空间失败就抛异常。

5 、new和delete的实现原理

内置类型

如果申请的是内置类型的空间,new和malloc,delete和free基本类似。

不同的地方是:

不new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续空间,而且new在申请空间失败时会抛异常,malloc会返回NULL。

自定义类型

new的原理

  1. 调用operator new函数申请空间
  2. 在申请的空间上执行构造函数,完成对象的构造

delete的原理

  1. 在空间上执行析构函数,完成对象中资源的清理工作
  2. 调用operator delete函数释放对象的空间

new T[N]的原理

  1. 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对

    象空间的申请。

  2. 在申请的空间上执行N次构造函数

delete[]的原理

  1. 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
  2. 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释
    放空间

6、定位new表达式(placement-new) (了解)

定位new表达式是在 已分配的原始内存空间中调用构造函数初始化一个对象。
使用格式:
new (place_address) type 或者new (place_address) type(initializer-list)

place_address必须是一个指针,initializer-list是类型的初始化列表

使用场景:

定位new表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如

果是自定义类型的对象,需要使用new的定义表达式进行显示调构造函数进行初始化

cpp 复制代码
class Test
{
public:
	Test(int date = 1)
		:_date(date)
	{
		cout << "Test()" << endl;
	}
	~Test()
	{
		cout << "~Test()" << endl;
	}
private:
	int _date;
};

int main()
{
	// pt现在指向的只不过是与Test对象相同大小的一段空间,还不能算是一个对象,因为构造函数没有执行
	Test* pt1 = (Test*)malloc(sizeof(Test));
	//new (place_address) type
	new(pt1)Test; // 注意:如果Test类的构造函数有参数时,此处需要传参

	//new(place_address) type(initializer - list)
	Test* pt2 = (Test*)malloc(sizeof(Test));
	new(pt2)Test(10);
}

7、总结:malloc/free和new/delete的区别

共同点:

  1. 都是从堆上申请空间,并且需要用户手动释放。

不同点:

  1. malloc和free是函数,new和delete是操作符

  2. malloc申请的空间不会初始化,new可以初始化

  3. malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可,

    如果是多个对象,[]中指定对象个数即可

  4. malloc的返回值为void*, 在使用时必须强转,new不需要,因为new后跟的是空间的类型

  5. malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需

    要捕获异常

  6. 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new

    在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成

    空间中资源的清理释放

相关推荐
Ajiang282473530437 分钟前
贪吃蛇项目实现(C语言)——附源码
c语言·开发语言
格林威3 小时前
Baumer工业相机堡盟工业相机如何通过BGAPISDK使用短曝光功能(曝光可设置1微秒)(C语言)
c语言·开发语言·人工智能·数码相机·计算机视觉
结衣结衣.4 小时前
Linux——进程状态
linux·运维·服务器·c语言·笔记·学习
格林威4 小时前
Baumer工业相机堡盟工业相机如何通过BGAPI SDK设置相机的图像剪切(ROI)功能(C语言)
c语言·开发语言·人工智能·数码相机·计算机视觉
少杰是小白4 小时前
计算机二级自学笔记(程序题1部分)
c语言·笔记
图像处理大大大大大牛啊5 小时前
使用mingw64 编译 QT开发流程
开发语言·c++·qt·命令模式
爱上杨小厨5 小时前
MFC实现对话框与控件的自适应调节
c++·mfc
Bill666 小时前
MFC之CString类及其成员函数用法详解
c++·mfc
Flame_Cyclone6 小时前
编写XBOX控制器实现鼠标键盘输入
c++·windows·win32·xbox·控制器模拟键盘鼠标
贩卖纯净水.6 小时前
共享内存喜欢沙县小吃
linux·运维·服务器·c++