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类型的空间并初始化为10return 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 5auto rs = unique(v.begin(), v.end());//将重复元素丢在后面:1 2 3 4 5 1 2 4v.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';elsecout << "找不到元素" << *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但是每个代码都有自己的运用场景

今天我们就介绍到这里啦

祝大家新年快乐 !!!

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

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

相关文章

楼宇智慧能源消耗监测管理系统,楼宇中的能源“管家”

随着人口的增加&#xff0c;楼宇数据呈上涨趋势&#xff0c;但是楼宇智能建设在我国普及性远远不足&#xff0c;相比传统楼宇控制&#xff0c;智能楼宇控制系统对于楼宇内部的用电设备控制&#xff0c;能够更加的节约能源&#xff0c;降低成本。对于现代化楼宇而言&#xff0c;…

ORACLE P6 v23.12 最新虚拟机(VM)全套系统环境分享

引言 根据上周的计划&#xff0c;我简单制作了两套基于ORACLE Primavera P6 最新发布的23.12版本预构建了虚拟机环境&#xff0c;里面包含了全套P6 最新版应用服务 此虚拟机仅用于演示、培训和测试目的。如您在生产环境中使用此虚拟机&#xff0c;请先与Oracle Primavera销售代…

C#最佳工具集合:IDE、分析、自动化工具等

C#是企业中广泛使用的编程语言&#xff0c;特别是那些依赖微软的程序语言。如果您使用C#构建应用程序&#xff0c;则最有可能使用Visual Studio&#xff0c;并且已经寻找了一些扩展来对您的开发进行管理。但是&#xff0c;这个工具列表可能会改变您编写C#代码的方式。 C#编程的…

模拟器怎么代理IP?代理IP对手机设置模拟器有哪些影响?

一、代理IP的基本概念和作用流冠代理IP是一种网络服务&#xff0c;可以帮助用户隐藏自己的真实IP地址&#xff0c;通过代理服务器进行网络请求&#xff0c;从而保护用户的隐私和安全。在模拟器中&#xff0c;代理IP的作用也是如此&#xff0c;可以帮助模拟器隐藏真实的IP地址&a…

Hubery-个人项目经历记录

研究生期间很有幸的进入到了崔老师的组&#xff0c;从此也就进入到了分析人体生理信号的领域&#xff0c;充满挑战的同时也充满了乐趣。借着CSDN整理一下近几年来参与的项目&#xff0c;这里蕴含着我各种美好的回忆&#xff0c;也作为一个展示自己的平台吧。 开始之前&#xff…

小红书12月内容趋势分析

为洞察小红书平台的内容创作趋势及品牌营销策略&#xff0c;新红推出12月月度榜单&#xff0c;从创作者、品牌、热搜词多方面入手&#xff0c;解析月榜数据&#xff0c;为从业者提供参考。 以下为12月部分榜单解析&#xff0c;想要查看更多行业榜单&#xff0c;创作优质内容&am…

【MySQL】常用存储引擎,数据库管理,数据表管理,数据库账户管理

目录 一 常用的数据引擎(4) 1.1 InnoDB存储引擎 1.2 MyISAM存储引擎 1.3 Memory存储引擎 1.4 ARCHIVE存储引擎 二 数据库管理 2.1 元数据库概念与分类 2.2 相关操作命令 三 数据表的管理 3.1 三大范式 3.2 数据类型 四 数据库账户管理 五 思维导图 一 常用的数据…

探索AliExpress商品详情API:使用与解析

一、引言 AliExpress是阿里巴巴旗下全球领先的B2C在线交易平台&#xff0c;为全球数亿消费者提供安全、便捷、高效的购物体验。随着电子商务的快速发展&#xff0c;获取商品详情成为了电商应用程序中的一项重要功能。AliExpress商品详情API&#xff08;aliexpress.item_get&am…

Vue中的选项式 API 和组合式 API,两者有什么区别

Vue中的选项式 API&#xff08;Option API&#xff09;和组合式 API&#xff08;Composition API&#xff09;是两种不同的组件编写方式&#xff0c;它们各有特点和适用场景&#xff1a; 选项式 API&#xff08;Option API&#xff09;: 传统方法&#xff1a;Vue最初的编程范式…

redis服务迁移数据工具--RDM

一、背景&#xff1a; 在日常的运维工作经常遇见各种数据迁移工作&#xff0c;例如mysql数据库迁移、redis数据库迁移、minio数据迁移等等工作。这里介绍一下redis数据库的迁移过程。 二、迁移思路&#xff1a; redis服务/集群的数据迁移思路是需要新建一个配置、密码一样的re…

【字典树Trie】LeetCode-139. 单词拆分

139. 单词拆分。 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s 。 注意&#xff1a;不要求字典中出现的单词全部都使用&#xff0c;并且字典中的单词可以重复使用。 示例 1&#xff1a; 输入: s "leetcode&q…

openGauss学习笔记-185 openGauss 数据库运维-升级-提交升级/升级版本回退/异常处理

文章目录 openGauss学习笔记-185 openGauss 数据库运维-升级-提交升级/升级版本回退/异常处理185.1 提交升级操作步骤 185.2 升级版本回滚操作步骤 185.3 异常处理升级问题FAQ openGauss学习笔记-185 openGauss 数据库运维-升级-提交升级/升级版本回退/异常处理 185.1 提交升级…

grep笔记240103

常用选项&#xff1a;&#xff1a; -i&#xff1a;忽略大小写进行匹配。 -v&#xff1a;反向匹配&#xff0c;只打印不匹配的行。 -n&#xff1a;显示匹配行的行号。 -r&#xff1a;递归查找子目录中的文件。 -l&#xff1a;只打印匹配的文件名。 -c&#xff1a;只打印匹配的行…

rk3588中编译带有ffmpeg的opencv

有朋友有工程需要&#xff0c;将视频写成mp4&#xff0c;当然最简单的方法当然是使用opencv的命令 cv::VideoWriter writer;bool bRet writer.open("./out.mp4", cv::VideoWriter::fourcc(m, p, 4, v), 15, cv::Size(640, 512), 1); 但是奈何很难编译成功&#xff…

NGUI基础-图集制作(保姆级教程)

目录 图集是什么 如何打开图集制作工具 制作步骤 图集的三个关键配置 相关参数介绍 Atlas Material Texture Padding Tim Alpha PMA shader Unity Packer TrueColor Auto-upgrade Force Square Pre-processor 图集是什么 Unity图集&#xff08;Sprite Atlas&…

AI:109-基于机器学习的文本图像关联分析

🚀点击这里跳转到本专栏,可查阅专栏顶置最新的指南宝典~ 🎉🎊🎉 你的技术旅程将在这里启航! 从基础到实践,深入学习。无论你是初学者还是经验丰富的老手,对于本专栏案例和项目实践都有参考学习意义。 ✨✨✨ 每一个案例都附带有在本地跑过的关键代码,详细讲解供…

SecOC中新鲜度值和MAC都按照完整的值来生成,但是在发送和认证的时候只会截取一部分。这边截取的部分一般取多长?由什么参数设定?

新鲜度值(Freshness Value, FV)和消息验证码(Message Authentication Code, MAC)是SecOC协议中用于保证数据的真实性和新鲜度的重要信息。它们的长度取决于不同的因素,如加密算法、安全级别、通信带宽等。 一般来说,FV和MAC的长度越长,安全性越高,但也会占用更多的通信…

ROS Gazebo的基本使用

Gazebo 提供了一个实时的三维虚拟环境&#xff0c;用于模拟各种复杂的真实世界条件&#xff0c;包括光照、地形、物理碰撞以及传感器模型&#xff08;如激光雷达、摄像头等&#xff09;。通过 ROS 和 Gazebo 的结合&#xff0c;开发者可以在无需实际硬件的情况下设计、测试和验…

2024,这将是量子计算的真正挑战

2023年&#xff0c;一项项量子计算纪录被打破。 谷歌量子AI团队证明了将多个量子比特分组合成为一个逻辑量子比特的纠错方法可以提供更低的容错率。以往的纠错研究随着比特数的增加&#xff0c;错误率会提高&#xff0c;都是“越纠越错”&#xff0c;而这次谷歌首次实现了“越纠…

低压线性恒流驱动芯片的产品特性与应用领域

低压线性恒流驱动芯片是一种具有多种产品特性的电子器件。 首先&#xff0c;它具有广泛的输入电压范围&#xff0c;可以适用于5V至80V的输入电压&#xff0c;使得其在不同的电源环境下都能正常工作。 低压线性恒流驱动芯片的产品特性与应用领域 其次&#xff0c;该芯片的输出…