C/C++内存管理,malloc,realloc,calloc,new,delete详解!!!

1.初步了解内存中各个区间存储的数据特征

1.栈区:存储一些局部变量、函数参数、返回值等,跟函数栈振有关,出了作用域,生命周期结束。

2.堆区:用于动态开辟空间,如果不主动销毁空间,则程序运行结束,生命周期结束。

3.数据段(静态区):static修饰的静态变量和全局变量,程序运行结束,生命周期结束。

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 . 代码段 ( 常量区 )
  globalVar 在哪里? __1__   staticGlobalVar 在哪里? __2__
  staticVar 在哪里? __3__   localVar 在哪里? __4__
  num1 在哪里? __5__
  char2 在哪里? __6__   * char2 在哪里? __7_
  pChar3 在哪里? __8__       * pChar3 在哪里? __9__
  ptr1 在哪里? __10__         * ptr1 在哪里? __11__
1.C       2.C       3.C        4. A       5.A       
6.A        7. A       8.A        9.D        10.A        11.B
结合上图可以得知,cha2其本身存放在栈区,指针指向栈区中数组首元素的地址,再将静态区中"abcd"赋值给数组,所以*char指向的元素在栈区!!!
pChar3其本身存放在栈区,指向静态区中存放"abcd"字符串的首地址!!!

2.c语言实现内存管理

2.1malloc

在堆上开一快符合你预期大小的一块空间,并且返回指向该地址空间的指针

void* malloc (size_t size);

size:开多大的空间,单位是字节

2.2realloc

如果malloc开辟出来的空间开少了,realloc可以在堆上重新开一块符合你预期大小的空间,并返回指向该空间的指针

void* realloc (void * ptr,size_t size);

ptr:初始空间的地址

size:将空间开辟到多大

 2.3calloc

用于对开辟的空间进行初始化,calloc会将开辟的空间中每个元素初始化为0

void* realloc (size_t num,size_t size);

num:分配的元素数量

size:每个元素的大小

3.c++实现内存管理

3.1 new/delete new []/delete []

在c++中,有两对操作符new/delete、new []/delete [],他们的作用是负责开空间和释放空间!!!

new作用跟malloc类似,delete作用跟free类似

new和delete在面对自定义类型时会去调用构造函数和析构函数

new =先申请对象空间 再调用构造函数

delete = 先调用析构函数 再释放对象空间

3.1.1内置类型

当需要开一个整形的空间时。

int main()
{ 
	//malloc
	int* p1 = (int*)malloc(sizeof(int));
	//new开空间用法跟malloc不同,但是作用相同,都是负责开空间!!!
	int* p2 = new int;

	//free
	free(p1);
	//delete
	delete(p2);
	return 0;
}

当需要开多个空间时 例如开10个int类型的空间 需要加上[]

int main()
{
	int* p1 = (int*)malloc(sizeof(int)*10);
	int* p2 = new int[10];

	free(p1);
	delete[](p2);
	return 0;
}
3.1.2自定义类型

new和delete在面对自定义类型时会去调用构造函数和析构函数

new =先开空间 再调用构造函数

delete = 先调用析构函数 再释放空间

class Stack
{
public:
	Stack(int capacity = 4)
	{
		_a = new int[capacity];
		int _top = 0;
		int _capacity = capacity;
	}
	~Stack()
	{
		delete (_a);
		_a = nullptr;
		_top = 0;
		_capacity = 0;
	}
private:
	int* _a;
	int _top;
	int _capacity;
};
int main()
{
	Stack* p2 = new Stack;
	//new先开空间 再去调用构造函数
	delete(p2);
	//delete先调用析构函数,再去释放空间
	return 0;
}

如果需要开10个Stack类型的空间 用new[] 和 delete[]

int main()
{
	Stack* p2 = new Stack[10];
	//new先开空间 再去调用构造函数
	delete[](p2);
	//delete先调用析构函数,再去释放空间
	return 0;
}

 3.2new/delete底层实现原理

3.2.1 全局函数 operator new/operator delete

要知道原理,我们就得先知道operatot new / operator delete 这两个全局函数

在c++中,有这样两个全局函数,他们的作用跟malloc、free类似,都是负责开空间和释放空间!!!

注意:operator new / operator delete 不是new/delete的重载,而是两个全局函数!!!

我们知道malloc申请空间失败的时候,会返回空。而operator new申请空间失败的时候则会抛异常。我们可以理解为operator是封装的malloc。

也就是说operator new 和mclloc除了申请空间失败的处理方法不同,其他的用法以及功能是相同的!!!

operator delete 可以理解为跟operator new对应,其用法和功能跟free完全一样!!!

int main()
{
	Stack* p1 = (Stack*)malloc(sizeof(Stack));
	free(p1);
	 
	//operator new底层用的是malloc
	Stack* p2 = (Stack*)operator new (sizeof(Stack));
	//operator delete底层用是free
	operator delete(p2);
	return 0;
}
3.2.2 new/delete 和 operator new/operator delete的关系

new = 1.申请对象空间 + 2.调用构造

delete = 1.调用析构 + 2.释放对象空间

在底层原理上,new的第一步申请对象空间底层就是调用operator new函数,

operator的第二步释放对象空间底层就是调用operator operator函数.

也就是说下面两段不同的代码,起到的作用都是相同的 

int main()
{
	Stack* p1 = new Stack;
	delete (p1);
	
    //等价于new
	Stack* p2 = (Stack*)operator new (sizeof(Stack));
	//定位new显示调用构造函数
	new(p2)Stack;
    //等价于delete
	p2->~Stack();
	operator delete(p2);
	return 0;
}

我们到汇编语言的角度证明一下

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

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

相关文章

Centos Bind安装与排错

1.配置Centos系统静态IP vi/etc/sysconfig/network-scripts/ifcfg-ens33BOOTPROTOstaticIPADDR192.168.1.100NETMASK255.255.255.0GATEWAY192.168.1.1DNS18.8.8.8:wqsudo systemctl restart network.service 2.安装BIND(需要服务器连接互联网,如果服务…

手把手教你实现一个循环队列(C语言)

这是一道leetcode关于队列的经典题: 622. 设计循环队列https://leetcode.cn/problems/design-circular-queue/ 思路: 大家注意这个题目要求,这个队列是定长的,如果满了则不能再添加数据。那么我们设计一个队头front和队尾rear&…

激光雷达SLAM(一)------初始激光雷达SLAM

专栏目的及认识激光雷达SLAM 一、专栏目的二、初始激光雷达SLAM1、激光雷达SLAM算法相关知识点2、SLAM常见问题[^2]3、激光雷达SLAM的需求点4、RTK在SLAM中的作用5、激光雷达视觉紧耦合图优化滤波紧耦合 一、专栏目的 大家好!介绍一下博主自己,感知算法工…

职场份子钱随不随?这20个真相你需要知道!

职场份子钱随不随?这20个真相你需要知道! 1.千万不要在老婆面前夸小姨子水灵。 2.盖世功劳,当不得一个矜字;弥天罪过,当不得一个悔字。 3.愚蠢的人永远只会根据答案判断难度。 4.改变自己的是神,企图改…

数据库基础教程之数据库的创建(一)

双击打开Navicat,点击:文件-》新建连接-》PostgreSQL 在下图新建连接中输入各参数,然后点击:连接测试,连接成功后再点击确定。 点击新建数据库 数据库设置如下:

51代码审计-PHP框架MVC类上传断点调试

知识点1,文件上传漏洞挖掘 搜索关键字$_FILES phpmvc架构 MVC模式(Model-View-Controller)是软件工程中的一种软件架构模式。 MVC把软件系统分为三个基本部分:模型(Model)、视图(View&#…

2024年最新最全的Jmeter接口测试必会技能:jmeter对图片验证码的处理

jmeter对图片验证码的处理 在web端的登录接口经常会有图片验证码的输入,而且每次登录时图片验证码都是随机的;当通过jmeter做接口登录的时候要对图片验证码进行识别出图片中的字段,然后再登录接口中使用; 通过jmeter对图片验证码…

LeetCode.203移除链表元素(原链表操作、虚拟头结点)

LeetCode.203移除链表元素 1.问题描述2.解题思路3.代码 1.问题描述 给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val val 的节点,并返回 新的头节点 。 示例 1: 输入:head [1,2,6,3,4,5,6], val …

保护模式进阶

本系列文章只做个人学习记录使用 参考资料: 《操作系统真象还原》 从0到-1写一个操作系统 获取物理内存容量 计算机要想被使用,就必须先管理,我们想和物理内存打交道,就必须先知道物理内存有多大 linux获取内存的方法 在linux…

C语言做一个恶作剧关机程序

一、项目介绍 C语言实现一个简单的"流氓软件"&#xff0c;一个可以强制关机恶作剧关机程序&#xff0c;输入指定指令可以解除 二、运行截图 然后当你输入“n”才可以解锁关机。 三、完整源码 #include <stdlib.h> #include <stdio.h> #include <s…

【挑战业余一周拿证】一、亚马逊云科技简介 - 第 2 节 - 模块 简介

CSDN 官方中文视频&#xff08;免费&#xff09;&#xff1a;点击进入 第 2 节 - 模块 1 简介 这门课程将为您提供需要了解的所有重要信息&#xff0c;让您能够轻松讨论亚马逊云科技并了解它为 何对您的企业有利 亚马逊云科技为每个企业都提供了非常广泛的服务&#xff0c;从…

【Linux】信号

Linux 信号 1.信号介绍2.core dump3.发送信号3.1.kill3.2.send3.3.abort 4.信号产生4.1.软件条件产生信号4.1.1.SIGPIPE4.1.2.SIGALRM 4.2.硬件异常产生信号 5.信号处理6.可重入函数 & volatile7.SIGCHLD 1.信号介绍 信号本质是一种通知机制。 而进程要处理信号&#xff0…

Docker Swarm总结+基础、集群搭建维护、安全以及集群容灾(1/4)

博主介绍&#xff1a;Java领域优质创作者,博客之星城市赛道TOP20、专注于前端流行技术框架、Java后端技术领域、项目实战运维以及GIS地理信息领域。 &#x1f345;文末获取源码下载地址&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3fb;…

PyQt6 QLabel标签控件

​锋哥原创的PyQt6视频教程&#xff1a; 2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~共计21条视频&#xff0c;包括&#xff1a;2024版 PyQt6 Python桌面开发 视频教程(无废话…

jQuery_08 each函数的使用

each函数的使用 可以循环数组&#xff0c;json&#xff0c;dom对象数组 1.$.each(要循环的内容,function(index,element){处理函数}) 要循环的内容可以是数组&#xff0c;json对象&#xff0c;dom数组 function&#xff1a;循环的处理函数 每个成员都会执行这个函数一次 index&…

5.golang字符串的拆解和拼接

字符串是 Go 中的字节切片。可以通过将一组字符括在双引号中来创建字符串" "。Go 中的字符串是兼容Unicode编码的&#xff0c;并且是UTF-8编码的。 访问字符串的单个字节或字符 由于字符串是字节切片&#xff0c;因此可以访问字符串的每个字节。 func printStr(s …

Spring Boot 项目中读取 YAML 文件中的数组、集合和 HashMap

在 Spring Boot 项目中&#xff0c;我们经常使用 YAML 文件来配置应用程序的属性。在这篇博客中&#xff0c;我将模拟如何在 Java 的 Spring Boot 项目中读取 YAML 文件中的数组、集合和 HashMap。 1. 介绍 YAML&#xff08;YAML Aint Markup Language&#xff09;是一种人类…

建造者模式-C语言实现

UML类图&#xff1a; 代码实现&#xff1a; #include <stdio.h> #include <stdlib.h>// 产品类 typedef struct {char* part1;char* part2;char* part3; } Product;// 抽象建造者类 typedef struct {void (*buildPart1)(void*, const char*);void (*buildPart2)(v…

2023-3年CSDN创作纪念日

机缘 今天开开心心出门去上班&#xff0c;就收到了一个csdn私信&#xff0c;打开一看说是给我惊喜来着&#xff0c;我心想csdn还能给惊喜&#xff1f;以为是有什么奖品或者周边之类的&#xff0c;结果什么也没有&#xff0c;打开就是一份信&#x1f602;。 也挺不错的&#xf…

java: nio之DirectByteBuffer

package nio;import java.nio.ByteBuffer; import java.nio.IntBuffer;public class DirectTest {public static void main(String[] args) {ByteBuffer byteBuffer ByteBuffer.allocateDirect(1024);} }