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

devtools/2024/9/20 13:40:10/ 标签: 学习

目录

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类型的空间并初始化为10int* ptr5 = new int(10);//管理对象数组// 动态申请10个int类型的空间int* ptr6 = new int[3];//动态申请10个int类型的空间,并初始化为1 2 3 4int* 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)); // Cint* 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.ppmy.cn/devtools/6469.html

相关文章

AI系列:大语言模型的function calling(下)- 使用LangChain

目录 前言LangChain Tool/Function calling1. Tool/function加强功能LangChain的tool装饰器其他方式: Pydantic 2. 绑定tools/functions3. 调用大模型(LLM)4. function calling处理流程 LangChain版代码与原生LLM调用的比较参考 前言 在AI系列&#xff1a;大语言模型的functio…

esp32s3中使用双通道通信解决TCP粘包问题

在使用esp32 idf例程中的tcp_server和tcp_client通信测试时发现&#xff0c; 在tcp_server端&#xff0c;接收到一帧数据之后必须马上回复至少一个字节&#xff0c;才能保证每帧数据不粘包&#xff0c; 如果不回复操作&#xff0c;300ms以内的通信时延会导致tcp严重粘包&…

Android AIDL接口

一.AlDI接口简介 AIDL&#xff08;Android Interface Definition Language&#xff09;是一种 IDL 语言&#xff0c;用于生成可以在 Android 设备上两个进程之间进行进程间通信&#xff08;IPC&#xff09;的代码。 通过 AIDL&#xff0c;可以在一个进程中获取另一个进程的数据…

XiaodiSec day028 Learn Note 小迪渗透学习笔记

XiaodiSec day028 Learn Note 小迪渗透学习笔记 记录得比较凌乱&#xff0c;不尽详细 day 28 还是 sql 注入 知识点 提交方式的注入 在 php, spring boot, flask 都有相关的提交方式 提交方式的注入 数据以某种方式提交到后端 数据大小和数据类型和提交方式有关 如身份…

uniapp之消除图片的空白占用空间

我们在使用uniapp开发的过程中一定会遇到一个情况就是我们加载的图片总有一点空白出现在不该出现的地方代码如下 <view style"background:#ff0000;"><image style"width:100%;"src"https://t7.baidu.com/it/u1819248061,230866778&fm19…

安卓广播发送接收流程

本文基于Andorid 11。 一、registerReceiver registerReceiver(new MyRecevier(), new IntentFilter("com.example.broadcast"));动态注册广播接收器&#xff0c;参数&#xff1a;BroadcastReceiver, IntentFilter。 <receiver android:name".MyReceiver&…

ubuntu在xshell中使用快捷方式操作命令,减少命令行的数入量

第一步 第二步 然后无脑确定 第三步 在xshell的显示方式 方式一 这样就会在每个窗格中进行显示 方式二 效果显示–> 这种窗格的显示是全局的 然后你双击这个process就会自动把命令打在命令行上&#xff0c;减少你的输入量

基于改进遗传算法的配电网故障定位(matlab代码)

1 主要内容 该程序复现文章《基于改进遗传算法的配电网故障定位》&#xff0c;将改进的遗传算法应用于配电网故障定位中, 并引入分级处理思想, 利用配电网呈辐射状的特点, 首先把整个配电网划分为主干支路和若干独立区域, 再利用该算法分别对各独立区域进行故障定位, 然后进行…

pdf做批注编辑工具 最新pdf reader pro3.3.1.0激活版

PDF Reader Pro是一款功能强大的PDF阅读和编辑工具。它提供了多种工具和功能&#xff0c;帮助用户对PDF文档进行浏览、注释、编辑、转换和签名等操作。以下是PDF Reader Pro的一些主要特色&#xff1a; 最新pdf reader pro3.3.1.0激活版下载 多种查看模式&#xff1a;PDF Reade…

海外云手机为什么适合社媒运营?

如今&#xff0c;社媒营销如果做得好&#xff0c;引流效果好的账号&#xff0c;可以用来带货变现&#xff0c;而外贸、品牌出海也同样都在做社媒营销&#xff0c;Tik Tok、facebook、ins等热门的海外社媒平台都是行业密切关注的&#xff0c;必要的时候&#xff0c;大家会使用海…

Linux进阶--文本处理grep、sed、awk命令

目录 一、grep &#xff08;1&#xff09;用文件查找 二、正则表达式 三、sed命令 四、awk命令 grep、sed、awk可以称作linux里的三驾马车 一、grep grep&#xff1a;一种强大的文本搜索工具&#xff0c;它能使用正则表达式匹配模式搜 索文本&#xff0c;并把匹配的行打…

故障转移-redis

4.4.故障转移 集群初识状态是这样的&#xff1a; 其中7001、7002、7003都是master&#xff0c;我们计划让7002宕机。 4.4.1.自动故障转移 当集群中有一个master宕机会发生什么呢&#xff1f; 直接停止一个redis实例&#xff0c;例如7002&#xff1a; redis-cli -p 7002 sh…

项目实战之网络电话本之发送邮件名片和导出word版个人信息

1、项目介绍 1&#xff09;项目功能 用户管理&#xff1a;分为管理员、和普通用户&#xff0c;设置不同用户的权限 电话本信息管理&#xff1a;支持管理员和普通用户对电话本的信息进行增删改操作&#xff0c;模糊查询&#xff08;根据姓名、地址、单位&#xff09; 文件批…

Ubuntu22.04下opencv4.9.0环境的搭建

目录 1、更新系统包列表:2、安装依赖项:3、下载 OpenCV 源代码:4、编译和安装 OpenCV:5、配置环境变量:6、测试1、更新系统包列表: 在终端中执行以下命令,以确保系统包列表是最新的: sudo apt update2、安装依赖项: 安装构建 OpenCV 所需的依赖项: sudo apt inst…

【GIS教程】ArcGIS做日照分析(附练习数据下载)

我国对住宅日照标准的规定是:冬至日住宅底层日照不少于1小时或大寒日住宅层日照不少于2小时(通常以当地冬至日正午12时的太阳高度角作为依据)。因冬至日太阳高度角最低&#xff0c;照射范围最小&#xff0c;如果冬至日12&#xff1a;00建筑物底层能够接收到阳光&#xff0c;那么…

基于SpringBoot+Vue的无人仓库管理系统 免费获取源码

项目源码获取方式放在文章末尾处 项目技术 数据库&#xff1a;Mysql5.7/8.0 数据表&#xff1a;8张 开发语言&#xff1a;Java(jdk1.8) 开发工具&#xff1a;idea 前端技术&#xff1a;vue 后端技术&#xff1a;SpringBoot 功能简介 (有文档) 项目获取关键字&#x…

[C语言][数据结构][链表] 双链表的从零实现!

目录 零.必备知识 0.1 一级指针 && 二级指针 0.2 双链表节点的成员列表 a. 数据 b. 后驱指针 c. 前驱指针 0.3 动态内存空间的开辟 一. 双链表的实现与销毁 1.1 节点的定义 1.2 双向链表的初始化 && 创建新节点 1.3 尾插 1.4 头插 1.5 尾删 1.6 头删 1…

关于机器学习/深度学习的一些事-答知乎问(六)

如何使用频率域变换对序列数据进行增强&#xff1f; 时频变换是常见的信号分析思路&#xff0c;同样可用于数据增强。在频率域添加噪声是方法之一。比如可以对传感器信号应用短时傅里叶变换STFT得到具有时序关系的谱特征&#xff0c;再在谱特征上应用两种数据增强方法。一是对…

【树莓派学习】hello,world!

系统安装及环境配置详见【树莓派学习】系统烧录及VNC连接、文件传输-CSDN博客 树莓派内置python3&#xff0c;可以直接利用python输出。

关于外网java后端服务访问内网minio中间件,因连接minio超时,启动失败问题

注&#xff1a;服务器情况&#xff1a;2台服务器&#xff0c;内网服务器包含&#xff08;activemq、minio、nginx、redis、mysql、后端java服务&#xff09;。外网服务器只有后端java服务&#xff0c;访问内网的中间件&#xff08;内网服务器开放了部分指定端口&#xff09; 问…