【C++第五课-C/C++内存管理】C/C++的内存分布、new/delete、new和delete的实现原理

目录

  • C/C++的内存分布
  • new/delete
    • new
      • 内置类型使用new
      • 自定义类型使用new
      • new失败
    • delete
      • 内置类型使用delete
      • 自定义类型使用delete
    • new和delete的实现原理
    • new[] 和delete[]的补充知识
  • 定位new(了解)
  • 常见面试题

C/C++的内存分布

在这里插入图片描述

频繁的new/delete堆容易产生内存碎片,栈上则没有这个问题(因为是连续分配)
栈是先进后出,先进的在内存地址大的
堆无法静态分配,只能动态分配
栈可以通过函数_alloca进行动态分配,不过注意,所分配空间不能通过free或delete进行释放
不同的数据有不同的存储需求,内存的个区间划分为了满足这些不同的需求
1、临时用(局部变量、数组等) - > 栈
2、动态使用(数据结构、算法中需要动态开辟一些空间) - > 堆
3、整个程序期间都要使用(全局变量,静态变量) - > 静态区/数据段
4、只读数据(常量、可执行代码) - > 代码段/常量区
可执行代码是指二进制代码(电脑可以看懂的那个)
咱写的那个代码存在磁盘上(存在文件中)
在这里插入图片描述

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);
}
选择题
选项: A.栈 B.堆 C.数据段(静态区) D.代码段(常量区)
1、globalVar在哪里?____ 2、staticGlobalVar在哪里?____
3、staticVar在哪里?____ 4、localVar在哪里?____
4、num1 在哪里?____
5、char2在哪里?____ 6*char2在哪里?___
7、pChar3在哪里?____ 8*pChar3在哪里?____
9、ptr1在哪里?____ 10*ptr1在哪里?____
填空题:
11sizeof(num1) = ____;
12sizeof(char2) = ____;  13strlen(char2) = ____;
14sizeof(pChar3) = ____; 15strlen(pChar3) = ____;
16sizeof(ptr1) = ____;

1、C globalVar是全局变量 - 在静态区
2、C staticGlobalVar是静态全局变量 - 在静态区
3、C staticVar是静态变量 - 在静态区
4、A num1是数组名指的是首元素地址 - 在栈上
5、A char2是数组名 - 在栈上
6、A *char2指向的是根据常量字符串创建的数组 - 在栈上
7、A pchar3是指针 - 在栈上
8、D *pchar3是值得常量字符串 - 在常量区
9、A ptr1是指针 - 在栈上
10、B *ptr1是指针指向的那块动态开辟的空间 - 在堆上

11、40
12、5
13、4 (strlen不算\0)
14、4/8
15、4
16、4/8

在这里插入图片描述

补充
1、下面三者的相同点与不同点
在这里插入图片描述
相同的:生命周期都是全局
不同点:作用域不同。globalVar是所有文件都可以使用;staticGlobalVar是只能当前文件使用;staticVar是只能在Test函数里面使用
2、const
(1)const char* pChar3 = "abcd" const修饰的是pChar3所指向的内容不能改变
(2)char* const pChar3 = "abcd" 这个const才是修饰pChar3这个指针的内容不能被修改
(3)const int n = 10 n是常变量
3、字面量
10、‘x’、“111111111”、1.1
4、calloc:开辟空间并初始化为0

new/delete

new

内置类型使用new

使用方法:new+类型
new对于内置类型不会初始化, 初始化(一个数据用(),多个数据用{})

//申请一个int空间
int* p1 = new int;
int* p2 = new int[3];//初始化
int* p3 = new int(3);
int* p41 = new int[3]{1, 2, 3};
int* p4 = new int[10]{1, 2, 3};//不用10个都初始化,前三个是123,后七个是0//释放
delete p1;
delete[] p2;
delete p3;
delete[] p41;
delete[] p4;

在这里插入图片描述

自定义类型使用new

malloc不方便解决动态申请的自定义类型对象的初始化问题
new:1、开空间; 2、调用构造函数

new失败

new失败了会抛异常,异常必须被捕获(继承和多态讲)
出错了之后会直接到捕获的地方(往catch的地方跳)

delete

内置类型使用delete

使用方法:new的就用delete;new[] 的就用delete[]

自定义类型使用delete

delete:析构函数 + 释放空间

new和delete的实现原理

new:operater new + 调用构造函数
delete:调用析构函数 + operater delete

operater new:封装了malloc,加了个出错时的报错机制
operater delete:封装了free,加了个出错时的报错机制
operater new和operater delete是函数,new和delete是操作符

new[] 和delete[]的补充知识

class Stack
{
public:Stack(int capacity = 4):_a(nullptr),_top(0),_capacity(capacity){_a = new int[capacity];}~Stack(){delete[] _a;_a = nullptr;_top = 0;_capacity = 0;}
private:int* _a;int _top;int _capacity;
};int main()
{Stack* p3 = new Stack[10];delete[] p3;return 0;
}

1、new[]的底层
因为p3指向的是个数据,空间上是连续的,因此new只调用了一次
在这里插入图片描述

2、new Stack[10]这个开辟的大小本应该120,但实际上是124
(1)new[]偷偷在最前面开了4字节放-- 一共开的对象数目

在这里插入图片描述
在这里插入图片描述

(2)delete[] 就会先将指针向前移动4字节,然后根据其内容知道是调用10次析构函数
(3)正是由于(2)条,delete时就不会将指针向前移动四个字节,因此报错
(4)但有时即使像(3),但也不会报错

class A
{
public:A(int a = 0):_a(a){cout << "A(int a)" << endl;}A(const A& i){_a = i._a;cout << "A(const A& i)" << endl;}/*~A(){cout << "~A()" << endl;}*/
private:int _a;
};
int main()
{A* p2 = new A[10];delete p2;return 0;
}

在这里插入图片描述

原因:
因为A没有析构函数,所以系统任务A的对象没有什么可析构的,调不调析构函数都可以,因此在new[]时会进行优化,直接不创建最前面的四个字节来显示一个创建了几个A对象
因此在delete的时候本来就不需要向前移动四个字节,所以不会报错

定位new(了解)

在已分配的原始内存空间中调用构造函数初始化一个对象

new(place_address)type或者new(place_address)type(initializer-list)

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

int main()
{A* p3 = (A*)operator new(sizeof(A));//定位new去调用构造函数,构造函数不能显示调用new(p3)A(1);//析构函数可以显示调用p3->~A();return 0;
}

定位new去调用构造函数,构造函数不能显示调用
析构函数可以显示调用

在这里插入图片描述
虽然上面的两行相当于new,一般情况下我们会用new(方便)
特殊情况我们也会用那两行
频繁申请小对象是,需要频繁的去堆上开辟空间池化技术,内存池
在这里插入图片描述

内存池
1、内存池申请对象空间
2、定位new显示调用构造函数
3、释放对象:显示调用析构函数,将内存还回内存池

常见面试题

用法+原理
malloc/free和new/delete的区别?
malloc/free和new/delete的共同点是:都是从堆上申请空间,并且需要用户手动释放。不同的地
方是:

  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在释放空间前会调用析构函数完成
    空间中资源的清理

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

算法学习——LeetCode力扣动态规划篇10(583. 两个字符串的删除操作、72. 编辑距离、647. 回文子串、516. 最长回文子序列)

算法学习——LeetCode力扣动态规划篇10 583. 两个字符串的删除操作 583. 两个字符串的删除操作 - 力扣&#xff08;LeetCode&#xff09; 描述 给定两个单词 word1 和 word2 &#xff0c;返回使得 word1 和 word2 相同所需的最小步数。 每步 可以删除任意一个字符串中的一个…

2023年第十四届蓝桥杯大赛软件类省赛C/C++研究生组真题(代码完整题解)

C题-翻转⭐ 标签:贪心 简述:如果 S 中存在子串 101 或者 010,就可以将其分别变为 111 和 000,操作可以无限重复。最少翻转多少次可以把 S 变成和 T 一样。 链接: 翻转 思路:要求步骤最少->S每个位置最多修改一次->从头开始遍历不匹配就翻转->翻转不了就-1 …

汇编语言——用INT 21H 的A号功能,输入一个字符串存放在内存,倒序输出

用INT 21H 的A号功能&#xff0c;输入一个字符串“Hello, world!”&#xff0c;存放在内存&#xff0c;然 后倒序输出。 在DOS中断中&#xff0c;INT 21H是一个常用的系统功能调用中断&#xff0c;它提供了多种功能&#xff0c;其中A号功能用于字符串的输入。 在使用这个功能时…

康耐视visionpro-CogAcqFifoTool工具详细说明

CogAcqFifoTool操作说明&#xff1a; ① 打开工具栏&#xff0c;双击或点击鼠标拖拽 添加CogAcqFifoTool ②.从图片采集设备/图像采集卡列表里选择对应的相机&#xff0c;视频格式选择图像格式。 Mono表示黑白图像&#xff0c;RGB表示彩色相机。点击初始化取相初始化相机。 ③…

灵动翻译音频文件字幕提取及翻译;剪映视频添加字幕

参考&#xff1a;视频音频下载工具 https://tuberipper.com/21/save/mp3 1、灵动翻译音频文件字幕提取及翻译 灵动翻译可以直接chorme浏览器插件安装&#xff1a; 点击使用&#xff0c;可以上传音频文件 上传后自动翻译&#xff0c;然后点击译文即可翻译成中文&#xff0c;…

排序——非基于比较的排序

本专栏和大家分享关于排序的算法,其中有插入排&#xff08;直接插入排序和希尔排序&#xff09;、选择排序&#xff08;直接选择排序和堆排&#xff09;、交换排序&#xff08;冒泡排序和快速排序&#xff09;、归并排序以及其他非基于比较的排序 本文与大家分享非基于比较的排…

MySQL学习之连接查询

笛卡尔乘积现象 在表的连接查询方面有一种现象被称为&#xff1a;笛卡尔积现象。 笛卡尔积现象&#xff1a; 当两张表进行连接查询的时候&#xff0c;没有任何条件进行限制&#xff0c;最终的查询结果条数是两张表记录条数的乘积。 select ename,dname from emp,dept; 避免…

算法系列--动态规划--特殊的状态表示--分析重复子问题

&#x1f495;"轻舟已过万重山!"&#x1f495; 作者&#xff1a;Lvzi 文章主要内容&#xff1a;算法系列–算法系列–动态规划–特殊的状态表示–分析重复子问题 大家好,今天为大家带来的是算法系列--动态规划--特殊的状态表示--分析重复子问题 一.组合总数IV 链接…

实现富文本的三部曲

1、引入 ueditor.config.js ueditor.all.min.js lang/zh-cn/zh-cn.js 2、编辑器显示处 id"content" <textarea id"content" name"content"></textarea> 3、底部 <script type"text/javascript"> //实例化编辑器 …

搜索与图论——Floyd算法求最短路

floyd算法用来求多源汇最短路 用邻接矩阵来存所有的边 时间复杂度O(n^3) #include<iostream> #include<cstring> #include<algorithm>using namespace std;const int N 20010,INF 1e9;int n,m,k; int g[N][N];void floyd(){for(int k 1;k < n;k ){f…

网络基础(二)——序列化与反序列化

目录 1、应用层 2、再谈“协议” 3、网络版计算器 Socket.hpp TcpServer.hpp ServerCal.hpp ServerCal.cc Protocol.hpp ClientCal.cc Log.hpp Makefile 1、应用层 我们程序员写的一个个解决我们实际问题&#xff0c;满足我们日常需求的网络程序&#xff0c;都是在…

QT+Opencv+yolov5实现监测

功能说明&#xff1a;使用QTOpencvyolov5实现监测 仓库链接&#xff1a;https://gitee.com/wangyoujie11/qt_yolov5.git git本仓库到本地 一、环境配置 1.opencv配置 将OpenCV-MinGW-Build-OpenCV-4.5.2-x64文件夹放在自己的一个目录下&#xff0c;如我的路径&#xff1a; …

appium辅助自动化工具-- Appium studio

这里我要给大家介绍一款appium辅助自动化测试工具appium studio&#xff0c;你没看错&#xff0c;不是android studio&#xff0c;也不是appium android studio&#xff0c;就是appium studio&#xff01; 下载地址&#xff1a; Appium Studio | Digital.ai Continuous Test…

智慧公厕的技术融合策略

智慧公厕是迎合现代城市发展需要的一项重要基础设施&#xff0c;其设计的技术融合策略在实现公共厕所泛在感知、互通互联、协同构筑智慧城市等方面起到了关键作用。本文将以智慧公厕源头实力厂家广州中期科技有限公司&#xff0c;大量精品案例现场实景实图实例&#xff0c;从物…

Makefile:动态库的编译链接与使用(六)

1、动态链接库 动态链接库&#xff1a;不会把代码编译到二进制文件中&#xff0c;而是运行时才去加载&#xff0c;所以只需要维护一个地址 动态&#xff1a;运行时才去加载&#xff0c;即所谓的动态加载连接&#xff1a;指库文件和二进制程序分离&#xff0c;用某种特殊的手段…

MySQL - 高阶语句(一)

先准备一张表 create table class1 (id int,name varchar(10) primary key not null ,score decimal(5,2),address varchar(20),hobbid int(5));insert into class1 values(1,liuyi,80,beijing,2); insert into class1 values(2,wangwu,90,shengzheng,2); insert into class1 …

图腾柱PFC:HP1010为您的电动两轮车之旅提供绿色,高效,安全的动力

电动两轮车不仅为当今生活提供了便利&#xff0c;更是一种健康和绿色的出行方式。想象一下&#xff0c;在经过一整晚的充分休息&#xff0c;骑上爱车&#xff0c;满血复活的准备开始新的一天。您会愿意带着如何给心爱的两轮车充电的担心开始这一天吗&#xff1f; 随着越来越…

第1章.提示词:开启AI智慧之门的钥匙

什么是提示词&#xff1f; 提示词&#xff0c;是引导语言模型的指令&#xff0c;让用户能够驾驭模型的输出&#xff0c;确保生成的文本符合需求。 ChatGPT&#xff0c;这位文字界的艺术大师&#xff0c;以transformer架构为基石&#xff0c;能轻松驾驭海量数据&#xff0c;编织…

JUC并发编程(七)

1、不可变对象 1.1、概念 不可变类是指一旦创建对象实例后&#xff0c;就不能修改该实例的状态。这意味着不可变类的对象是不可修改的&#xff0c;其内部状态在对象创建后不能被更改。不可变类通常具有以下特征&#xff1a; 实例状态不可改变&#xff1a;一旦不可变类的对象被…

中药知识分享

中药知识分享 声明&#xff1a;本文根据《懒兔子》公众号公益视频整理&#xff0c;参考网络信息略有改动&#xff0c;图片来源于网络&#xff0c;如有侵权&#xff0c;请联系删除。文章内容如有不正确之处请指正批评。仅供学习使用。请勿擅自服用本文提及的药材&#xff0c;否…