C++学习————第八天(C/C++内存管理)

news2024/12/26 23:49:41

目录

1、1.C/C++内存分布

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

3、C++内存管理方式

3.1 new/delete操作内置类型

3.2 new和delete操作自定义类型

4.operator new与operator delete函数

5. new和delete的实现原理

5.1 内置类型   

5.2 自定义类型

>)delete注意事项

1、1.C/C++内存分布

我们先来看下面的一段代码和相关问题

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__
  
  分析:
  globalVar全局变量在数据段 staticGlobalVar静态全局变量在静态区
  staticVar静态局部变量在静态区  localVar局部变量在栈区
  num1局部变量在栈区

  char2在哪里?__A__  *char2在哪里?__A__
  pChar3在哪里?__A__   *pChar3在哪里?__D__
  ptr1在哪里?__A__    *ptr1在哪里?__B__
  
  分析:
  char2局部变量在栈区  
  char2是一个数组,把后面常量串拷贝过来到数组中,数组在栈上,所以*char2在栈上
  pChar3局部变量在栈区   *pChar3得到的是字符串常量字符在代码段
  ptr1局部变量在栈区     *ptr1得到的是动态申请空间的数据

【说明】

1、栈又叫堆栈–非静态局部变量/函数参数/返回值等等,栈是向下增长的。
2、内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信。(现在只需要了解, 后面在linux中会提到)
3、堆用于程序运行时动态内存分配,堆是可以上增长的。
4、数据段–存储全局数据和静态数据。
5、代码段–可执行的代码/只读常量。


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


void Test()
{
	int* p1 = (int*)malloc(sizeof(int));
	free(p1);
	// 1.malloc/calloc/realloc的区别是什么?
	int* p2 = (int*)calloc(4, sizeof(int));
	int* p3 = (int*)realloc(p2, sizeof(int) * 10);
	// 这里需要free(p2)吗?
	free(p3);
}

1. malloc/calloc/realloc的区别?

三者都是分配内存,都是stdlib.h库里的函数,但是也存在一些差异。

(1)malloc函数。其原型void *malloc(unsigned int num_bytes);
              num_byte为要申请的空间大小,需要我们手动的去计算,如int *p = (int*)

malloc( 20*sizeof(int)),如果编译器默认int为4字节存储的话,那么计算结果是80Byte,一次申请一个80Byte的连续空间,并将空间基地址强制转换为int类型,赋值给指针p,此时申请的内存值是不确定的。

(2)calloc函数,其原型void *calloc(size_t n, size_t size);
        其比malloc函数多一个参数,并不需要人为的计算空间的大小,比如如果他要申请20个int类型空间,会int *p = (int *)calloc(20, sizeof(int)),这样就省去了人为空间计算的麻烦。但这并不是他们之间最重要的区别,malloc申请后空间的值是随机的,并没有进行初始化,而calloc却在申请后,对空间逐一进行初始化,并设置值为0;

既然calloc不需要计算空间并且可以直接初始化内存避免错误,那为什么不直接使用calloc函数,那要malloc要什么用呢?
实际上,任何事物都有两面性,有好的一面,必然存在不好的地方。这就是效率。calloc函数由于给每一个空间都要初始化值,那必然效率较malloc要低,并且现实世界,很多情况的空间申请是不需要初始值的,这也就是为什么许多初学者更多的接触malloc函数的原因。

(3)realloc函数和上面两个有本质的区别,其原型void realloc(void *ptr, size_t new_Size)
用于对动态内存进行扩容(及已申请的动态空间不够使用,需要进行空间扩容操作,ptr为指向原来空间基址的指针, new_size为接下来需要扩充容量的大小。


3、C++内存管理方式

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

3.1 new/delete操作内置类型

void Test()
{
	//内置类型

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

	//管理对象数组
	// 动态申请10个int类型的空间
	int* ptr6 = new int[3];
	//动态申请10个int类型的空间,并初始化为1 2 3 4
	int* ptr7 = new int[10] {1, 2, 3, 4}; //后面的会默认初始化为0
	
	//释放一个对象
	delete ptr4; 
	delete ptr5;
	//释放多个对象
	delete[] ptr6; 
	delete[] ptr7;
}

注意:申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用new[]和delete[],注意:匹配起来使用。

3.2 new和delete操作自定义类型

       new/delete 和 malloc/free最大区别是 new/delete对于【自定义类型】除了开空间还会调用构造函数和析构函数

class A
{
public:
	A(int a = 0)
		: _a(a)
	{
		//cout << "A():" << this << endl;
		cout << "A():" << endl;

	}
	A(int a1, int a2)
	{
		cout << "A(int a1, int a2)" << endl;
	}
	
	A(const A& aa)
		: _a(aa._a)
	{
		cout << "A(const A& aa)" << endl;
	}
	A& operator=(const A& aa)
	{
		cout << "A& operator=(const A& aa)" << endl;
		if (this != &aa)
		{
			_a = aa._a;
		}
		return *this;
	}

	~A()
	{
		//cout << "~A()" << this << endl;
		cout << "~A()" << endl;

	}
private:
	int _a;
};

int main()
{
	// new/delete 和 malloc/free最大区别是
	// new/delete对于【自定义类型】除了开空间,还会调用构造函数和析构函数
	A* p1 = (A*)malloc(sizeof(A));
	A* p2 = new A(2);
	free(p1);
	delete p2;

	// 内置类型是几乎是一样的
	int* p3 = (int*)malloc(sizeof(int)); // C
	int* p4 = new int;
	free(p3);
	delete p4;

	A* p5 = (A*)malloc(sizeof(A) * 10);
	A* p6 = new A[10]; //调用10次构造函数
	free(p5);
	delete[] p6; //调用10次析造函数

	//多个对象
	A aa1(1);
	A aa2(2);
	A aa3(3);
	A* p7 = new A[10]{ aa1,aa2,aa3 };
	delete[]p7;
	// 多参数
	A* p7 = new A[10]{ 1,2,3,4,5,{6,7}};//用1生成临时对象,然后被编译器合二为一(隐式对象转换)
	delete[]p7;


	return 0;
}

注意:在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc与free不会

4.operator new与operator delete函数

1.new和delete是用户进行动态内存申请和释放的操作符,operator new 和operator delete是系统提供的全局函数
2.new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局 函数来释放空间。

5. new和delete的实现原理

5.1 内置类型   

  如果申请的是内置类型的空间,new和malloc,delete和free基本类似,不同的地方是:
new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续空间,而且new在申请空间失败时会抛异常,malloc会返回NULL。

5.2 自定义类型

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来释
放空间

总结:new == operator new -> (malloc) + 构造函数
           ~~~~~~~~~~          delete == 析构函数 + operator delete -> (free)
           ~~~~~~~~~~          特别的:new失败了,抛异常, 不需要再检查返回值

>)delete注意事项

ClassA *pclassa=new ClassA[5];
delete pclassa;

析构函数此时只会调用1次,要想完整释放数组空间,需要使用[]
注意:程序可能崩溃

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1613812.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++ 初识模板

目录 0.前言 1.泛型编程 2.函数模板 2.1概念 2.2格式 2.3原理 2.4函数模板的实例化 2.4.1隐式实例化 2.4.2显式实例化 2.5模板参数的匹配原则 3.类模板 3.1类模板的定义格式 3.2类模板的实例化 4.结语 &#xff08;图像由AI生成&#xff09; 0.前言 在 C 中&a…

密码学 | 承诺:常见的承诺方案

&#x1f951;原文&#xff1a;密码学原语如何应用&#xff1f;解析密码学承诺的妙用 - 知乎 1 简介 密码学承诺 涉及 承诺方、验证方 两个参与方&#xff0c;以及以下两个阶段&#xff1a; 承诺阶段&#xff1a;承诺方选择一个敏感数据 v v v&#xff0c;为它计算出相应…

docker打包部署自己的应用

docker部署应用 当谈及使用 Docker 进行容器化部署应用时&#xff0c;可以想象它是一个能够将整个应用程序及其所有依赖项打包成一个独立、可移植的容器的工具。这个容器不仅包含了应用代码&#xff0c;还包括了操作系统、运行时环境以及所有依赖的库和组件。这样一来&#xf…

Python 全栈安全(二)

原文&#xff1a;annas-archive.org/md5/712ab41a4ed6036d0e8214d788514d6b 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 第二部分&#xff1a;认证与授权 本书的第二部分是最具商业价值的部分。我这样说是因为它充满了大多数系统需要具备的实用工作流示例&#xf…

nginxtomcat笔记

nginx是一个轻量级高性能的http和反向代理web服务器&#xff0c;优点&#xff1a;占用内存少&#xff0c;并发能力强 实验主机&#xff1a;192.168.200.141 192.168.200.142 1.虚拟主机 1.1基于域名&#xff1a;一台服务器&#xff0c;一个端口&#xff0c;部署多个网站 在ng…

Transformer - Teacher Forcing

Transformer - Teacher Forcing flyfish 在训练过程中&#xff0c;将目标序列输入给解码器的方法称为&#xff08;Teacher Forcing&#xff09;。这个术语又代表什么意思呢&#xff1f; 这里的目标序列就是Ground Truth&#xff0c;也就是我们已知的正确答案 一句话就是我们…

火灾风险把控:数据采集卡搭配传感器实现电路异常全面监控!

引言 在现代社会中&#xff0c;火灾安全和用电安全是人们生活和工作中不可忽视的重要问题。为了有效应对火灾风险和电路异常情况&#xff0c;阿尔泰科技引入了一项创新解决方案&#xff1a;利用PXIe5681多功能数据采集卡对小信号的高精度测量优势&#xff0c;搭配电压传感器监…

使用代理绕过网站的反爬机制

最近在尝试收集一些网络指标的数据&#xff0c; 所以&#xff0c; 我又开始做爬虫了。 :) 我们在做爬虫的过程中经常会遇到这样的情况&#xff0c;最初爬虫正常运行&#xff0c;正常抓取数据&#xff0c;一切看起来都是那么的美好&#xff0c;然而一杯茶的功夫可能就会出现错误…

文本嵌入新方案:合合信息acge模型荣登C-MTEB榜首

目录 0 写在前面1 文本嵌入&#xff1a;LLM落地的根基2 C-MTEB&#xff1a;acge荣夺榜一2.1 max tokens2.2 文本分类2.3 文本聚类 3 acge demo演示与体验总结 0 写在前面 随着信息技术的发展和应用场景的不断扩大&#xff0c;人们需要处理和利用大量的文档信息。而传统的手动处…

深度学习transformer架构详细详解

一、transformer的贡献 transformer架构的贡献&#xff1a;该架构只使用自注意力机制&#xff0c;没有使用RNN或卷积网络。且可以实现并行计算&#xff0c;加快模型训练速度。 &#xff08;将所有的循环层全部换成&#xff1a;multi-headed self-attention&#xff09; 二、t…

39. UE5 RPG角色释放技能时转向目标方向

在上一篇&#xff0c;我们实现了火球术可以向目标方向发射&#xff0c;并且还可以按住Shift选择方向进行攻击。技能的问题解决&#xff0c;现在人物释放技能时&#xff0c;无法朝向目标方向&#xff0c;接下来我们解决人物的问题。 实现思路&#xff1a; 我们将使用一个官方的…

C++ //练习 12.20 编写程序,逐行读入一个输入文件,将内容存入一个StrBlob中,用一个StrBlobPtr打印出StrBlob中的每个元素。

C Primer&#xff08;第5版&#xff09; 练习 12.20 练习 12.20 编写程序&#xff0c;逐行读入一个输入文件&#xff0c;将内容存入一个StrBlob中&#xff0c;用一个StrBlobPtr打印出StrBlob中的每个元素。 环境&#xff1a;Linux Ubuntu&#xff08;云服务器&#xff09; 工…

密码学 | Random Oracle 随机预言机

​ &#x1f951;原文&#xff1a;究竟什么才是随机预言机呢&#xff1f; - 玄星的回答 &#x1f951;答主指出&#xff1a; 英文维基明明对 随机预言机 给出了两个完全不同的理解&#xff0c;但这两个理解之间的连接词却是 “Stated differently”&#xff0c;即 “换句话说…

LabVIEW多设备控制与数据采集系统

LabVIEW多设备控制与数据采集系统 随着科技的进步&#xff0c;自动化测试与控制系统在工业、科研等领域的应用越来越广泛。开发了一种基于LabVIEW平台开发的多设备控制与数据采集系统&#xff0c;旨在解决多设备手动设置复杂、多路数据显示不直观、数据存储不便等问题。通过RS…

c语言利用控制台实现贪吃蛇

使用控制台实现贪吃蛇需要的技能加点&#xff1a; 控制台设置&#xff08;包含于stdlib.h&#xff09;&#xff1a; 定义命令行窗口高/宽&#xff1a; system("mode con cols100 lines30"); system() 函数是一个C标准库函数&#xff0c;它允许程序执行操作系统命令…

Java中创建对象内存分析

package day31; ​ public class Pet {String name;int age;public void shout(){System.out.println("叫了一声");} } ​ package day31; ​ public class Application {public static void main(String[] args) {Pet cat new Pet();cat.name"肥波";cat…

Linux——网络管理nmcli

nmcli 不能独立使用&#xff0c;需要对应的服务启动 1. NetworkManager.service 2. 网络配置和服务不相关 3. 通过 nmcl &#xff49; 建立网络配置和网卡之前的映射关系 网卡 简称&#xff1a;nmcli d DEVICE &#xff1a;物理设备 TYPE: 物理设备类型 ethernet 以太网…

螺纹滑牙的原因有哪些——SunTorque智能扭矩系统

螺纹滑牙的原因&#xff0c;通常是由于在旋紧或旋松过程中&#xff0c;螺纹副之间的摩擦力不足以维持所需的预紧力或工作载荷&#xff0c;导致螺纹副的相对位置发生变化。这种现象可能由多种因素引起&#xff0c;包括材料选择不当、设计不合理、制造工艺缺陷、环境因素以及使用…

AI大模型探索之路-实战篇3:基于私有模型GLM-企业级知识库开发实战

文章目录 前言概述一、本地知识库核心架构回顾&#xff08;RAG&#xff09;1. 知识数据向量化2. 知识数据检索返回 二、大模型选择1. 模型选择标准2. ChatGLM3-6B 三、Embedding模型选择四、改造后的技术选型五、资源准备1. 安装git-lfs2. 下载GLM模型3. 下载Embeding模型 六、…

Java、Spring、Dubbo三者SPI机制原理与区别

Java、Spring、Dubbo三者SPI机制原理与区别 什么是SPI SPI全称为Service Provider Interface&#xff0c;是一种动态替换发现的机制&#xff0c;一种解耦非常优秀的思想&#xff0c;SPI可以很灵活的让接口和实现分离&#xff0c;让api提供者只提供接口&#xff0c;第三方来实…