C/C++动态内存分配 malloc、new、vector(简单讲述)

路虽远,行则将至

事虽难,做则必成

今天来主要讲C++中动态内存分配

其中会穿插一些C的内容以及两者的比较

如果对C语言中的动态内存分配还不够理解的同学

可以看看我之前的博客:C语言动态分配


在讲解C++的动态内存分配之前

我们先讲一下C++内存模型 :

C++内存分配模型

C++程序在执行时,将内存大方向划分为4个区域:


代码区:存放函数体的二进制代码,由操作系统进行管理的
全局区:存放全局变量和静态变量以及常量
栈区:由编译器自动分配释放,存放函数的参数值,局部变量
堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收



意义:不同区域存放的数据,赋予不同的生命周期,给我们更大的灵活编程

栈区内存和堆区内存的区别

栈区内存是由编译器管理的,出了定义域就会被系统销毁

这里用代码展示:

#include<iostream>
using namespace std;
int* fun()
{
	int a = 10;              //局部变量存放在栈区,栈区的数据在函数执行完后释放
	return &a;               //返回变量a的地址
}
int main()
{
	int* p = fun();          //接受函数fun的返回值
	cout << "" << *p << endl;//这里能打印10是因为编译器在释放的会进行一次保留
	cout << "" << *p << endl;//这里出现乱码是因为空间被编译器销毁了
	system("pause");
	return 0;
}

 

1.第一次打印原值是因为编译器在释放时会进行一次保留

2.第二次出现乱码是因为出函数定义域空间被编译器销毁

由于栈区的内存出了定义域会被系统销毁不满足某些程序需求

于是我们引进了由程序员掌控的动态内存  


堆区内存(也就是我们说的动态内存)是由我们程序员分配的,由程序员进行管理

C++中动态内存开辟关键字new

我们可以通过newdelete(关键字)操作符进行动态内存管理

#include<iostream>
using namespace std;
int* fun()
{
	                     //利用new关键字可以将数据开辟到堆区
	int* p = new int(10);//动态申请一个int类型的空间并初始化为10
	return p;
}
int main()
{
	int* ptr = fun();
	cout << "" << *ptr << endl;
	cout << "" << *ptr << endl;
	delete ptr;//释放空间
	system("pause");
	return 0;
}

1.数据10是开辟在堆区的在程序没有结束之前是由程序员控制 

2.指针本质也是局部变量放在栈上指针保存的数据是放在堆区

 new还可以申请连续的空间:

#include<iostream>
using namespace std;
int main()
{
	int* a = new int[5];
	for (int i = 0; i < 5; i++)
	{
		a[i] = i;
	}
	for (int i = 0; i < 5; i++)
	{
		cout << "" << a[i] << endl;
	}
	delete[] a;
	system("pause");
	return 0;
}


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

 C&C++的动态开辟的区别

首先我们在介绍一下C语言中malloc开辟动态空间

#include<stdio.h>
#include<malloc.h>
#include<assert.h>
using namespace std;
int* fun()
{
	int* p = (int*)malloc(sizeof(int));//开辟空间
	assert(p);//断言开辟释放成功
	*p = 10;
	return p;
}
int main()
{
	int* ptr = fun();
	printf("%d\n", *ptr);
	printf("%d\n", *ptr);
	free(ptr);//释放空间
	system("pause");
	return 0;
}

 C&C++的动态开辟的区别:

相同点:

都是从堆上申请空间,并且需要用户手动释放

不同点:


1. malloc free 函数 new delete 操作符

2. malloc申请的空间不会初始化new可以初始化


3. malloc申请空间时,需要手动计算空间大小并传递new只需在其后跟上空间的类型即可

如果是多个对象,[]中指定对象个数即可

4. malloc的返回值为void*, 使用时必须强转new不需要,因为new后跟的是空间的类型


5. malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new

要捕获异常

 C++中vector开辟动态数组

template < class T, class Alloc = allocator<T> > class vector

容器的大小:vector是一个动态数组,可以根据需要自动调整大小一 它会根据素的数量动态分配内存空间


vector还可以使用一些功能:


vector增删查改
接口说明
push_back (重点) 尾插
pop_back   (重点) 尾删
find  查找(注意这个是算法模块实现,不是vector 的成员接口)
insert 在position 之前插入 val
erase 删除position 位置的数据
swap 交换两个vector 的数据空间
operator[ ]   (重点) 像数组一样访问

选代器

 vector提供了迭代器,可以用于遍历容器中的元素。可以使用 begin() 函数获取指向第个元素的迭代器,使用 end() 函数获取指向最后一个元素之后位置的迭代器


容器大小管理

可以使用 size() 函数获取vector中元素的数量,使用 empty() 函数检查vector是否为空


元素访问

可以通过索引来访闻vector中的元素。索引从0开始,最后一个元素的索引是 size 可以使用[]运算符或 at() 函数来访元素

接下来我们将介绍vector的常见用法(记得包含头文件#include <vector>哦):

vector的初始化(1)

vector开辟5个整型大小的连续空间,未赋初值

<>尖括号为元素类型名,它可以是任何合法的数据类型

#include<iostream>
#include<vector>
using namespace std;
int main()
{
	vector<int> a(5);//开辟动态数组
	for (int i = 0; i < 5; i++)
	{
		a[i] = i;
	}
	for (int i = 0; i < 5; i++)
	{
		cout << a[i] << " ";
	}
	return 0;
} 

 vector的初始化(2)

开辟5个整型大小的空间并赋值为1

#include<iostream>
#include<vector>
using namespace std;
int main()
{
	vector<int> a(5,1);
	for (int i = 0; i < 5; i++)
	{
		cout << a[i] << " ";
	}
	return 0;
} 

vector的初始化(3)

vector<int> v = { 1,3,5,7,9,2,4,6,8,0 };

可以直接给动态数组赋初值

vector的常见用法(1):push_back

作用:将元素添加到vector的末尾

#include<iostream>
#include<vector>
using namespace std;
int main()
{
	vector<int> v;
	for (int i = 0; i < 10; ++i)
	{
		v.push_back(i);//尾插
	}
	for (int i = 0; i < 10; ++i)
	{
		cout << v[i] << " ";
	}
	return 0;
}

#include<iostream>
#include<vector>
using namespace std;
int main()
{
	vector<int> v;
	v.push_back(5);
	v.push_back(2);
	v.push_back(8);
	v.push_back(1);
	v.push_back(5);
	for (int i = 0; i < v.size(); i++)//size计算数组的长度
	{
		cout << v[i] << " ";
	}
	return 0;
}

vector的常见用法(2):迭代器

常用于排序

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main()
{
	vector<int> v = { 1,3,5,7,9,2,4,6,8,0 };
	sort(v.begin(), v.end());
	for (int i = 0; i < v.size(); i++)
	{
		cout << v[i] << " ";
	}
	return 0;
}

vector的常见用法(3):erase

常用于排序去重

首先,需要对vector进行排序,以便相同的元素相邻。

然后,unique函数将重复的元素移动到vector的末尾,并返回一个指向第一个重复元素的迭代器

最后,可以使用v.erase函数将重复元素从vector中删除

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
	vector<int> v = { 2,1,3,2,4,1,5,4 };
	sort(v.begin(), v.end());            //排序:1 1 2 2 3 4 4 5
	auto rs = unique(v.begin(), v.end());//将重复元素丢在后面:1 2 3 4 5 1 2 4
	v.erase(rs, v.end());                //从第一个重复元素开始到结束的都删除
	for (const auto& num : v)
	{
		cout << num << " ";
	}
	return 0;
}

vector的常见用法(4):empty

常用来检查vector是否为空

#include <iostream>
#include <vector>
using namespace std;
int main()
{
	vector<int> v;
	v.push_back(5);
	v.push_back(2);
	v.push_back(0);
	v.erase(v.begin() + 2);//删除位置3的元素
	if (v.empty())
	{
		cout << "vector为空" << endl;
	}
	else
	{
		cout << "vector不为空" << endl;
	}
	for (int i = 0; i < v.size(); i++)
	{
		cout << v[i] << " ";
	}
	cout << "\n";
	v.clear();//清空vector中的元素
	if (v.empty())
	{
		cout << "vector为空" << endl;
	}
	else
	{
		cout << "vector不为空" << endl;
	}
	return 0;
}

vector的常见用法(5):find

在任何容器中查找指定元素,返回一个迭代器指向第一个匹配的元素

常用于在一组数据中查找某一元素是否存在

#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
    vector<int> v = { 1,3,5,7,9,2,4,6,8,0};
    auto it = find(v.begin(), v.end(), 3);
    if (it != v.end())
        cout << "找到了元素 " << *it << '\n';
    else
        cout << "找不到元素" << *it << '\n';
}

vector的常见用法(6):pop_back 

常用于删除末尾元素

#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
    vector<int> v = { 1,3,5,7,9,2,4,6,8,0};
    v.pop_back();
    v.pop_back();
    v.pop_back();
    for (int i = 0; i < v.size(); i++)
    {
        cout << v[i] << " ";
    }
    return 0;
}

我们可以清晰的看到末尾的三个元素被删除了

vector的功能很强大,我感觉完全碾压malloc、new但是每个代码都有自己的运用场景

今天我们就介绍到这里啦

祝大家新年快乐 !!!

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

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

相关文章

Java+springboot+vue智慧校园源码,数据云平台Web端+小程序教师端+小程序家长端

技术架构&#xff1a; Javaspringbootvue element-ui小程序电子班牌&#xff1a;Java Android演示自主版权。 智慧校园电子班牌人脸识别系统全套源码&#xff0c;包含&#xff1a;数据云平台Web端小程序教师端小程序家长端电子班牌 学生端。 电子班牌系统又称之为智慧班牌&am…

低代码平台受到欢迎的原因有哪些?

在当今快速发展的数字化时代&#xff0c;应用程序开发已成为企业不可或缺的关键环节。传统的代码开发方式虽然稳定、强大&#xff0c;但对于许多企业来说&#xff0c;其耗时、成本高昂且对技术要求较高&#xff0c;因此&#xff0c;低代码开发被越来越多的企业选择。 低代码开发…

Jenkins的环境部署,(打包、发布、部署、自动化测试)

一、Tomcat环境安装 1.安装JDK&#xff08;Java环境&#xff09; JDK下载地址&#xff1a;Java Downloads | Oracle 安装好后在系统环境变量里配置环境变量&#xff1a; ①添加JAVA_HOME 变量名&#xff1a;JAVA_HOME变量值&#xff1a;C:\Program Files\Java\jdk1.8.0_18…

《设计模式》之策略模式

策略模式定义 比如对象的某个行为&#xff0c;在不同场景有不同实现方式&#xff0c;可以将这些行为的具体实现定义为一组策略&#xff0c;每个实现类实现种策略&#xff0c;在不同场景使用不同的实现&#xff0c;并且可以自由切换策略。 策略模式结构 策略模式需要一个策略…

如何用二维码看视频?视频做成二维码的快捷教程

现在将视频存入二维码中之后&#xff0c;让其他人通过扫码的方式来看视频是一种很流行的方式&#xff0c;那么视频是怎么制作成二维码的呢&#xff1f;对于想要学习制作视频二维码的小伙伴&#xff0c;可以学习一下本篇文章带来的制作方法&#xff0c;通过二维码视频生成器就可…

量子计算突破5G通信MIMO优化!真机测试完整报告公开!

​摘要&#xff1a;在无线通信领域&#xff0c;大规模多输入多输出 (MIMO&#xff09;是一项革命性技术&#xff0c;也是5G系统的关键技术之一&#xff0c;它主要利用基站上的大量天线来提高无线通信系统的覆盖范围和容量。通过波束赋形&#xff0c;大规模MIMO可以同时提供多种…

工业物联网中的网络建设是如何实现的?——青创智通工业物联网

在工业物联网的应用中&#xff0c;如何进行网络建设&#xff0c;对于青创智通工业物联网来说&#xff0c;车间内所有装备均可通过与OPC UA网关连接实现数据采集&#xff0c;OPC UA网关实现Modbus协议、DLT645协议、BACnet协议、CJ188协议、三菱协议、西门子协议、Mbus协议。 通…

大数据开发与低代码:加速数据处理与解决方案开发

随着数据量的爆炸式增长&#xff0c;大数据开发变得愈发重要。然而&#xff0c;传统的大数据开发方法往往需要复杂的编码和开发过程&#xff0c;消耗时间和资源。而低代码开发平台的出现为大数据开发带来了全新的解决方案。本文将介绍大数据开发和低代码的概念&#xff0c;并探…

零售EDI:Metro EDI项目案例

麦德龙Metro 总部位于杜塞尔多夫&#xff0c;在全球范围内经营批发和零售业务。在2018/2019 财年&#xff0c;麦德龙Metro 的全球销售额约为 270 亿欧元。从2016年开始&#xff0c;麦德龙Metro就开始对其当时约230家门店和20,000多家分销合作伙伴进行数字化整合&#xff0c;借助…

UseContentHash选项能否在打包AssetBundle时计算可靠的Hash

1&#xff09;UseContentHash选项能否在打包AssetBundle时计算可靠的Hash 2&#xff09;如何清理Native Reserved部分的内存 3&#xff09;Addressables资源完整性校验 4&#xff09;通过Image.color和CanvasRenderer.SetColor修改UI组件颜色的区别 这是第368篇UWA技术知识分享…

kubernetes(K8s)的使用和常用命令

K8S kubernetes&#xff0c;由于k和s之间有8个字符&#xff0c;所以简称k8s&#xff0c;是一个全新的基于容器技术的分布式架构领先方案&#xff0c;是谷歌严格保密十几年的秘密武器----Borg系统的一个开源版本&#xff0c;于2015年7月发布第一个正式版本&#xff0c;它的本质…

密码学:一文看懂Base64算法

文章目录 前言什么是Base64&#xff1f;Base64算法的由来Base64算法的定义Base64算法与加密算法的关系实现原理非ASCII码字符编码传递模型应用场景电子邮件传输网络数据传输密钥存储数字证书 参考 前言 Base64常常在我们开发中出现&#xff0c;我们可能只知道它是一串乱码&…

60m长H型钢在线测长与切割是如何做到的?

H型钢是断面形状类似于大写拉丁字母H的一种经济断面型材&#xff0c;又叫万能钢梁、宽缘(边)工字钢或平行翼缘工字钢。应用范围广&#xff0c;各种民用和工业建筑结构&#xff0c;各种大跨度的工业厂房和现代化高层建筑&#xff0c;大型桥梁等均可看到H型钢的身影。 它应用所在…

opencv入门到精通——Canny边缘检测

目录 理论 OpenCV中的Canny Edge检测 附加资源 在本章中&#xff0c;我们将学习 Canny边缘检测的概念 OpenCV函数: cv.Canny() 理论 Canny Edge Detection是一种流行的边缘检测算法。它由John F. Canny发明 1.这是一个多阶段算法&#xff0c;我们将经历每个阶段。 2.降…

C 练习实例19

题目&#xff1a;一个数如果恰好等于它的因子之和&#xff0c;这个数就称为"完数"。例如61&#xff0b;2&#xff0b;3.编程找出1000以内的所有完数。 程序分析&#xff1a;请参照&#xff1a;C 练习实例14。 步骤分析&#xff1a; 写一个函数判断是否是完数 找出…

Avalonia学习(十七)-CEF

今天开始继续Avalonia练习。 本节&#xff1a;CefNet 1.引入 CefNet.Avalonia.Eleven 2.项目引入 Program中加入 using Avalonia; using Avalonia.ReactiveUI; using Avalonia.Threading; using CefNet; using System; using System.IO; using System.Linq; using System…

[足式机器人]Part2 Dr. CAN学习笔记-自动控制原理Ch1-10奈奎斯特稳定性判据-Nyquist Stability Criterion

本文仅供学习使用 本文参考&#xff1a; B站&#xff1a;DR_CAN Dr. CAN学习笔记-自动控制原理Ch1-10奈奎斯特稳定性判据-Nyquist Stability Criterion Cauchy’s Argument Priciple 柯西幅角原理 结论&#xff1a; s s s平面内顺时针画一条闭合曲线 A A A&#xff0c; B B B曲…

Python从入门到网络爬虫(函数详解)

前言 函数是变成语言中最常见的语法&#xff0c;函数的本质就是功能的封装。使用函数可以大大提高编程效率与程序的可读性。函数是能够实现特定功能的计算机代码而已&#xff0c;他是一种特定的代码组结构。 函数的作用 1.提升代码的重复利用率&#xff0c;避免重复开发相同代…

【代数学作业1-python实现GNFS一般数域筛】构造特定的整系数不可约多项式:涉及素数、模运算和优化问题

代数学作业1-完整版&#xff1a;python实现GNFS一般数域筛 写在最前面背景在GNFS算法中选择互质多项式时&#xff0c;需要考虑哪些关键因素&#xff0c;它们对算法的整体运行时间有何影响? 练习1题目题目分析Kleinjung方法简介通用数域筛法&#xff08;GNFS&#xff09;中的多…

简易机器学习笔记(七)计算机视觉基础 - 常用卷积核和简单的图片的处理

前言 这里实际上涉及到了挺多有关有关理论的东西&#xff0c;可以详细看一下paddle的官方文档。不过我这里不过多的谈有关理论的东西。 【低层视觉】低层视觉中常见的卷积核汇总 图像处理中常用的卷积核 在代码中&#xff0c;我们实际上是用不同的卷积核来造成不同的影响&a…