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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JUC并发编程(七)

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

Linux(CentOS7)安装软件方式(编译安装,yum,rpm)

目录 前言 安装方式 编译安装 下载 解压 安装 创建软链接 yum rpm 前言 在使用 CentOS 安装软件时&#xff0c;发现安装的方式有好几种&#xff0c;有官网下载 tar 包解压&#xff0c;然后自己编译安装的&#xff0c;也有直接通过 yum 命令一键安装的&#xff0c;还有…

物联网实战--入门篇之(五)嵌入式-IIC驱动(SHT30温湿度)

目录 一、IIC简介 二、IIC驱动解析 三、SHT30驱动 四、总结 一、IIC简介 不管是IIC还是串口&#xff0c;亦或SPI&#xff0c;它们的本质区别在于有各自的规则&#xff0c;就是时序图&#xff1b;它们的相同点就是只要你理解了时序图&#xff0c;你就可以用最普通的IO引脚模…

PetaLinux安装详解(Xilinx , linux, zynq, zynqMP)

1 概述 PetaLinux 工具提供在 Xilinx 处理系统上定制、构建和调配嵌入式 Linux 解决方案所需的所有组件。该解决方案旨在提升设计生产力&#xff0c;可与 Xilinx 硬件设计工具配合使用&#xff0c;以简化针对 Versal、Zynq™ UltraScale™ MPSoC、Zynq™ 7000 SoC、和 MicroBl…

Docker 哲学 - push 本机镜像 到 dockerhub

注意事项&#xff1a; 1、 登录 docker 账号 docker login 2、docker images 查看本地镜像 3、注意的是 push镜像时 镜像的tag 需要与 dockerhub的用户名保持一致 eg&#xff1a;本地镜像 express:1 直接 docker push express:1 无法成功 原因docker不能识别 push到哪里 …

【JavaEE初阶系列】——CAS

目录 &#x1f388;什么是 CAS &#x1f4dd;CAS 伪代码 &#x1f388;CAS 是怎么实现的 &#x1f388;CAS 有哪些应用 &#x1f6a9;实现原子类 &#x1f308;伪代码实现: &#x1f6a9;实现自旋锁 &#x1f308;自旋锁伪代码 &#x1f388;CAS 的 ABA 问题 &#…

详解MQTT(Message Queuing Telemetry Transport)通信机制

目录 概述 1 认识MQTT 1.1 MQTT的定义 1.2 MQTT实现原理 1.3 MQTT架构的几个概念 1.3.1 MQTT Broker 1.3.2 MQTT Client 1.3.3 发布消息 1.3.4 订阅消息 2 认识MQTT报文结构 2.1 MQTT消息体结构 2.1.1 认识主题&#xff08;Topic&#xff09; 2.1.2 认识QoS(Qualit…

判断一个数据能否同时被3和5整除

一、运行结果&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff1b;int a 0;//提示用户printf("请输入一个整数\n");//获取用户输入数据&#xff1b;scanf("%d", &am…

WiFiSpoof for Mac wifi地址修改工具

WiFiSpoof for Mac&#xff0c;一款专为Mac用户打造的网络隐私守护神器&#xff0c;让您在畅游互联网的同时&#xff0c;轻松保护个人信息安全。 软件下载&#xff1a;WiFiSpoof for Mac下载 在这个信息爆炸的时代&#xff0c;网络安全问题日益凸显。WiFiSpoof通过伪装MAC地址&…

[图像处理] MFC载入图片并进行二值化处理和灰度处理及其效果显示

文章目录 工程效果重要代码完整代码参考 工程效果 载入图片&#xff0c;并在左侧显示原始图片、二值化图片和灰度图片。 双击左侧的图片控件&#xff0c;可以在右侧的大控件中&#xff0c;显示双击的图片。 初始画面&#xff1a; 载入图片&#xff1a; 双击左侧的第二个控件…

【uC/OS-III篇】uC/OS-III 移植到 STM32 简明教程

uC/OS-III 移植到 STM32 简明教程 一、uC/OS-III 介绍 二、获取UCOS-III源码 三、建立项目工程 四、解决工程编译报错 五、修改项目文件 下一篇博客&#xff1a; 【uC/OS-III篇】uC/OS-III 创建第一个任务&#xff08;For STM32&#xff09; 一、uC/OS-III 介绍 uC/OS-III…

docker部署开源软件的国内镜像站点

下载镜像 docker pull registry.cn-beijing.aliyuncs.com/wuxingge123/le_monitor:latestdocker-compose部署 vim docker-compose.yml version: 3 services:le_monitor:container_name: le_monitorimage: registry.cn-beijing.aliyuncs.com/wuxingge123/le_monitor:latestpo…

【JDK常用的API】包装类

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏 …

SQL Server 数据库常见提权总结

前面总结了linux和Windows的提权方式以及Mysql提权&#xff0c;这篇文章讲讲SQL Server数据库的提权。 目录 基础知识 权限判定 系统数据库 存储过程 常见系统存储过程 常见扩展存储过程 xp_cmdshell扩展存储过程提权 xp_dirtree写入文件提权 sp_oacreate提权 xp_re…

每日面经分享(Spring Boot: part2 DAO层)

1. Spring Boot DAO层的作用 a. 封装数据访问逻辑&#xff1a;DAO层的主要责任是封装与数据访问相关的逻辑。负责处理与数据库的交互&#xff0c;包括数据的增删改查等操作。通过将数据访问逻辑统一封装在DAO层中&#xff0c;可以提高代码的可维护性和可重用性。 b. 解耦业务逻…

学习笔记】java项目—苍穹外卖day05

文章目录 苍穹外卖-day05课程内容1. Redis入门1.1 Redis简介1.2 Redis下载与安装1.2.1 Redis下载1.2.2 Redis安装 1.3 Redis服务启动与停止1.3.1 服务启动命令1.3.2 客户端连接命令1.3.3 修改Redis配置文件1.3.4 Redis客户端图形工具 2. Redis数据类型2.1 五种常用数据类型介绍…

vsphere高可用实验

实验要求&#xff1a; 部署高可用集群&#xff0c;在2个EXSI主机上&#xff0c;将该虚拟机断电。这台虚拟机会在另一台主机上自动起来 实验环境要求&#xff1a; 2台EXSI&#xff0c;一台ISCSI&#xff0c;一台vcenter&#xff0c;在一台EXSI上安装一台虚拟机&#xff0c;要求…

武汉大学开设 “雷军班”:计算机专业、今年招收 15 名本科生。武汉大学已经联合小米成立了机器系

更多精彩内容在公众号。 3月25日&#xff0c;武汉大学官方网站发布了一则新闻&#xff0c;报道了校长张平文对计算机学院的调研活动。在报道中&#xff0c;张平文校长特别强调了关于“雷军班”及机器人系的发展规划。他表示&#xff0c;希望计算机学院能够立足于更高层次&#…

AI预测福彩3D第22弹【2024年3月31日预测--第5套算法开始计算第4次测试】

今天&#xff0c;咱们继续进行本套算法的测试&#xff0c;今天为第四次测试&#xff0c;仍旧是采用冷温热趋势结合AI模型进行预测。好了&#xff0c;废话不多说了。直接上结果~ 仍旧是分为两个方案&#xff0c;1大1小。 经过人工神经网络计算并进行权重赋值打分后&#xff0c;3…

MTMT:构建比特币生态平行世界 打造铭文生态繁荣

近年来&#xff0c;随着铭文市场的火爆以及比特币ETF成功通过&#xff0c;比特币生态正经历着一场复兴&#xff0c;尤其是铭文市场作为新一代Web3的叙事&#xff0c;带来了全新的生产方式&#xff0c;可以预见&#xff0c;铭文就像流动性挖矿对于上一轮DeFi Summer的推动一样会…