C++——vector的了解与使用
目录
引言
vector容器的基本概念
1.功能
2.动态大小
3.动态扩展
vector的接口
1.vector的迭代器
2.vector的初始化与销毁
3.vector的容量操作
3.1 有效长度和容量大小
(1)使用示例
(2)扩容机制
3.2 有效长度和容量操作
(1)reserve
(2)resize
4.vector的访问操作
5.vector的修改操作
迭代器失效
结束语
引言
在我的博客 C++——string的了解和使用 中,我们学习了标准模板库(STL)中的string的一些基础内容,今天我们来学习 vector 。
vector容器的基本概念
在C++中,vector 是一个非常重要的容器,它属于标准模板库的一部分。vector 提供了一种动态数组的实现,可以在运行时动态地增加或减少其大小,同时保持元素的连续存储。
1.功能
vector是可变大小的序列容器,采用连续存储空间存储元素,可通过下标高效访问。
2.动态大小
与静态数组不同,vector 的大小可以在运行时动态地改变。此外,静态数组内数据通常存储在栈上,而vector中数据存储在堆上。
3.动态扩展
动态扩展的核心在于,当现有内存空间不足以满足需求时,不是简单地在原空间后续接新空间(这在连续内存分配中通常是不现实的,因为后续空间可能已被其他程序或数据占用),而是采取以下步骤:
(1)分配新空间:找到一个足够大的、连续的新内存空间。这个新空间的大小要能够容纳原数据和新数据。
(2)数据拷贝:将原内存空间中的数据复制到新分配的内存空间中。这个过程中需要确保数据的完整性和正确性。
(3)释放原空间:在数据成功拷贝到新空间后,释放原来的内存空间。这一步是为了避免内存泄漏。
(4)更新指针:将指向原内存空间的指针更新为指向新内存空间的指针。这样,程序就可以继续在新空间中操作数据。
此外,使用vector时必须包含头文件 #include<vector> 。
vector的接口
我们使用如下文档来辅助我们学习vector:
vector的接口详细介绍
1.vector的迭代器
与string一样,vector中也有迭代器。由于vector定义在vector类中,因此我们想要使用vector的迭代器需要通过域作用限定符访问——vector<类型>::iterator 。
其中,begin(),end(),rbeign(),rend()的使用访问方法与string中的类似,
我们来看看代码演示:
int main()
{vector<int> vec = { 0,1,2,3,4,5,6,7,8,9 };vector<int>::iterator it = vec.begin();cout << "顺序遍历:";while (it != vec.end()){cout << *it << " ";it++;}cout << endl;cout << "逆序遍历:";vector<int>::reverse_iterator rit = vec.rbegin();while (rit != vec.rend()){cout << *rit << " ";++rit;}return 0;
}
输出结果如下:
同样的,vector也支持const_iterator:
int main()
{vector<int> vec = { 0,1,2,3,4,5,6,7,8,9 };for (vector<int>::const_iterator it = vec.begin(); it != vec.end(); ++it) {std::cout << *it << " ";}std::cout << std::endl;return 0;
}
2.vector的初始化与销毁
vector 类的赋值运算符 operator= 被重载以支持将一个 vector 的内容复制到另一个 vector 中。
vector 支持多种构造函数,拷贝构造以及赋值运算符重载。
下面是一些简单的使用:
void printVector(vector<int>& vec)
{ for (vector<int>::iterator it = vec.begin(); it != vec.end(); ++it){cout << *it << " ";}cout << endl;
}int main()
{vector<int> vec1; for (int i = 0; i < 5; ++i){vec1.push_back(i);}vector<int> vec2(vec1.begin(), vec1.end()); vector<int> vec3(5, 5); vector<int> vec4(vec3); cout << "打印vec2: ";printVector(vec2);cout << "打印vec3: ";printVector(vec3);cout << "打印vec4: ";printVector(vec4);return 0;
}
输出结果为:
int main()
{vector<int> vec1, vec2;for (int i = 0; i < 5; i++){vec1.push_back(i);}vec2 = vec1;printVector(vec2);return 0;
}
输出结果为:
3.vector的容量操作
如下表格是关于vector的一些基础的容量操作:
函数名称 | 功能 |
size | 返回vector的有效长度 |
capacity | 返回vector的容量大小 |
clear | 清空vector |
empty | 检查vector是否为空,是则返回ture,否则返回false |
reserve | 请求改变vector的容量 |
resize | 重新设置有效元素的数量,超过原来有效长度则用c字符填充 |
3.1 有效长度和容量大小
(1)使用示例
与 string类 类似,我们可以使用 size()返回容器的有效长度;capacity()返回容器的容量大小。
下面是简单的测试用例:
int main()
{vector<int> vec = { 0,1,2,3,4,5,6,7,8,9 };cout << vec.size() << endl;cout << vec.capacity() << endl;if (vec.empty()){cout << "vec为空" << endl;}else{cout << "vec不为空" << endl;}vec.clear();if (vec.empty()){cout << "vec为空" << endl;}else{cout << "vec不为空" << endl;}return 0;
}
输出结果为:
通常来说,vector的有效长度和容量大小相同
(2)扩容机制
接下来我们来看看vector的扩容机制:
int main()
{size_t sz;vector<int> vec;sz = vec.capacity();cout << "making vec grow:" << endl;for (int i = 0; i < 100; ++i){vec.push_back(i);if (sz != vec.capacity()){sz = vec.capacity();cout << "capacity changed: " << sz << endl;}}
}
输出结果为:
在vs2022中,vector是以1.5倍进行扩容处理的,
我们现在把这段代码放到g++中运行看看:
我们可以看到,在此环境中,vector是以二倍进行扩容的。
3.2 有效长度和容量操作
接下来我们来学习vector中的reserve和resize(这俩函数的使用与string中的差不多)。
(1)reserve
reserve 函数用于请求改变容器的容量,即分配足够的内存空间以容纳至少指定数量的元素
简单使用一下:
int main()
{vector<int> vec;vec.reserve(10);cout << vec.capacity() << endl;return 0;
}
输出结果为:
(2)resize
resize的使用有如下两种:
resize(int num);
如果 num 小于当前容器的大小,那么容器末尾的多余元素将被删除。如果 num 大于当前容器的大小,则容器将被扩展,新添加的元素将被初始化为该类型的默认值(对于内置类型如 int,默认值为 0)。
resize(int num, int elem);
这个方法同样用于将 std::vector 的大小调整为 num,但在容器需要扩展时,新添加的元素将被初始化为 elem 而不是默认值。如果 num 小于当前容器的大小,多余元素的处理方式与第一个 resize 方法相同,即被删除。
简单的使用一下:
int main()
{vector<int> vec = { 1,2,3,4,5 };vec.resize(3);for (int i = 0; i < vec.size(); i++){cout << vec[i] << " ";}cout << endl;vec.resize(4);for (int i = 0; i < vec.size(); i++){cout << vec[i] << " ";}cout << endl;vec.resize(5, 9);for (int i = 0; i < vec.size(); i++){cout << vec[i] << " ";}cout << endl;return 0;
}
输出结果为:
4.vector的访问操作
vector的访问操作有如下几个:
函数名称 | 功能 |
operator[] | 返回指定位置的元素,越界则报错 |
at | 返回指定位置的元素,越界则抛异常 |
front | 返回字符串第一个元素 |
back | 返回字符串最后一个元素 |
这些函数的用法也与string中的函数用法差不多,就不多介绍了,来看看代码:
int main()
{vector<int> vec = { 0,1,2,3,4,5,6,7,8,9 };for (int i = 0; i < vec.size(); i++){cout << vec[i] << " ";}cout << endl;for (int i = 0; i < vec.size(); i++){cout << vec.at(i) << " ";}cout << endl;cout << "front:" << vec.front() << endl;cout << "back:" << vec.back() << endl;return 0;
}
输出结果为:
5.vector的修改操作
vector的修改操作有如下几个:
函数名称 | 功能 |
push_back | 在数组后追加元素 |
pop_back | 删除数组最后一个元素 |
insert | 在指定位置追加元素 |
assign | 使用指定数组替换原数组 |
erase | 删除数组指定部分区间 |
swap | 交换两个数组 |
先来看看push_back(),pop_back(),assign(),swap() :
int main()
{vector<int> vec1 = { 0,1,2,3,4,5,6,7,8,9 };cout << "back:" << vec1.back() << endl;// 元素尾插vec1.push_back(10);// 元素尾删cout << "back:" << vec1.back() << endl;vec1.pop_back();cout << "back:" << vec1.back() << endl;vector<int> vec2 = { 9,9,9,9,9 };vec2.assign(3, 3);for (int i = 0; i < vec2.size(); i++){cout << vec2[i] << " ";}cout << endl;vec2.swap(vec1);for (int i = 0; i < vec1.size(); i++){cout << vec1[i] << " ";}cout << endl;for (int i = 0; i < vec2.size(); i++){cout << vec2[i] << " ";}cout << endl;return 0;
}
输出结果如下:
我们再来看看insert和erase:
insert函数:
来看代码:
int main()
{vector<int> vec1(5, 10);vector<int>::iterator it = vec1.begin();it = vec1.insert(it, 100);cout << "vec1:";for (it = vec1.begin(); it < vec1.end(); it++){cout << *it << " ";}cout << endl;vec1.insert(it, 2, 1000);it = vec1.begin();cout << "vec1:";for (it = vec1.begin(); it < vec1.end(); it++){cout << *it << " ";}cout << endl;vector<int> vec2(2, 10000);it = vec1.begin();vec1.insert(it + 2, vec2.begin(), vec2.end());cout << "vec1:";for (it = vec1.begin(); it < vec1.end(); it++){cout << *it << " ";}cout << endl;return 0;
}
输出结果为:
erase函数:
简单的代码演示如下:
int main()
{vector<int> vec = { 0,1,2,3,4,5,6,7,8,9 };vector<int>::iterator it = vec.erase(vec.begin() + 3); // 删除值为3的元素it = vec.erase(it); // 删除值为4的元素for (int i = 0; i < vec.size(); i++){cout << vec[i] << " ";}cout << endl;it = vec.erase(vec.begin(), vec.begin() + 5);for (int i = 0; i < vec.size(); i++){cout << vec[i] << " ";}cout << endl;return 0;
}
输出结果为:
迭代器失效
迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对 指针进行了封装,比如:vector的迭代器就是原生态指针T* 。因此迭代器失效,实际就是迭代器 底层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间,造成的后果是程序崩溃(即 如果继续使用已经失效的迭代器,程序可能会崩溃)。
以下可能会导致迭代器失效:
1.会引起其底层空间改变的操作,都有可能使迭代器失效
int main()
{vector<int> v{ 1,2,3,4,5,6 };auto it = v.begin();// 将有效元素个数增加到100个,多出的位置使用8填充,操作期间底层会扩容// v.resize(100, 8);// reserve的作用就是改变扩容大小但不改变有效元素个数,操作期间可能会引起底层容量改变// v.reserve(100);// 插入元素期间,可能会引起扩容,而导致原空间被释放// v.insert(v.begin(), 0);// v.push_back(8);// 给vector重新赋值,可能会引起底层容量改变//v.assign(100, 8);/*出错原因:以上操作,都有可能会导致vector扩容,也就是说vector底层原理旧空间被释放掉,而在打印时,it还使用的是释放之间的旧空间,在对it迭代器操作时,实际操作的是一块已经被释放的空间,而引起代码运行时崩溃。解决方式:在以上操作完成之后,如果想要继续通过迭代器操作vector中的元素,只需给it重新赋值即可。 */while (it != v.end()){cout << *it << " ";++it;}cout << endl;return 0;
}
2.指定位置元素的删除操作--erase
int main()
{int a[] = { 1, 2, 3, 4 };vector<int> v(a, a + sizeof(a) / sizeof(int));// 使用find查找3所在位置的iteratorvector<int>::iterator pos = find(v.begin(), v.end(), 3);// 删除pos位置的数据,导致pos迭代器失效。v.erase(pos);cout << *pos << endl; // 此处会导致非法访问return 0;
}
3.与vector一样,string在插入+扩容操作+erase之后,迭代器也会失效
int main()
{string s("hello");auto it = s.begin();// 放开之后代码会崩溃,因为resize到20会string会进行扩容// 扩容之后,it指向之前旧空间已经被释放了,该迭代器就失效了// 后序打印时,再访问it指向的空间程序就会崩溃//s.resize(20, '!');while (it != s.end()){cout << *it;++it;}cout << endl;it = s.begin();while (it != s.end()){it = s.erase(it);// 按照下面方式写,运行时程序会崩溃,因为erase(it)之后// it位置的迭代器就失效了// s.erase(it); ++it;}return 0;
}
结束语
写完啦~\(≧▽≦)/~
接下来会愈加忙碌,希望自己还能挤出时间写博客=_=
感谢各位大佬的支持!!!
求点赞收藏评论关注!!!
相关文章:

C++——vector的了解与使用
目录 引言 vector容器的基本概念 1.功能 2.动态大小 3.动态扩展 vector的接口 1.vector的迭代器 2.vector的初始化与销毁 3.vector的容量操作 3.1 有效长度和容量大小 (1)使用示例 (2)扩容机制 3.2 有效长度和容量操作 (1)reserve (2)resize 4.vector的访问操作…...
Ubuntu设置静态IP地址
Ubuntu如果是最小安装,没有图形界面,需要配置静态IP,该怎么操作呢? Netplan 是最新版 Ubuntu 的默认网络管理工具。Netplan 的配置文件使用 YAML 编写,扩展名为 .yaml。 注意:配置文件中的空格是语法的一部…...
力扣349.两个数组的交集
题目链接:349. 两个数组的交集 - 力扣(LeetCode) 给定两个数组 nums1 和 nums2 ,返回 它们的 交集。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。 示例 1: 输入:nums1 [1,2,…...

FreeRTOS - 软件定时器
在学习FreeRTOS过程中,结合韦东山-FreeRTOS手册和视频、野火-FreeRTOS内核实现与应用开发、及网上查找的其他资源,整理了该篇文章。如有内容理解不正确之处,欢迎大家指出,共同进步。 1. 软件定时器 软件定时器也可以完成两类事情…...
Python的Atlassian第三方库的详细介绍
atlassian-python-api 是一个用于与 Atlassian 生态系统进行交互的 Python 库,支持与多种 Atlassian 工具(如 Jira、Confluence、Bitbucket 等)进行 API 调用。它简化了 REST API 的调用,提供了高层次的抽象,方便开发者…...
Java中的基本循环结构详解
在Java编程中,循环是控制流的重要组成部分,用于重复执行一段代码。Java提供了三种基本的循环结构:for循环、while循环和do-while循环。本文将详细介绍这三种循环的语法和使用场景,并通过示例代码展示其应用。 一,for …...

关于Git Bash中如何定义alias
一、在一次临时Bash会话中使用alias 在Bash中直接输入alias xxdddd,xx为对应要执行的命令的缩写,dddd为要执行的命令,如alias ddcd /d,输入完成后,在Bash中输入dd,即可切换至D盘。 此种设置方式ÿ…...

luckfox1106初次使用
luckfox1106初次使用 下载rk驱动 https://files.luckfox.com/wiki/Luckfox-Pico/Software/DriverAssitant_v5.12.zip 安装驱动 SD 卡烧录工具 https://files.luckfox.com/wiki/Luckfox-Pico/Software/SocToolKit_v1.98_20240705_01_win.zip 右键以管理员方式运行...
ab命令深入解析:ApacheBench性能测试工具
软考鸭微信小程序 学软考,来软考鸭! 提供软考免费软考讲解视频、题库、软考试题、软考模考、软考查分、软考咨询等服务 引言 在Web开发和运维领域,性能测试是评估服务器和应用性能的重要手段。ApacheBench(简称ab)是Apache HTTP服务器自带的…...

VSCode创建VUE项目(二)前端登录页面
一.创建登录页面 代码: <template><div class"login-container dis-h"><div class"login-form dis-h"><div class"dis-v left"><span> 欢迎~ </span><span> VUE 新世界 </span>&l…...

centos 8.4学习小结
1.权限委派 2.vim快捷方式 2.1非正常关闭文本处理方式 2.2快捷方式 2.3TAB键补齐安装包 [ rootcloud Packages]# rpm -ivh bash-completion-2.7-5.el8.noarch.rpm 2.4#history 查询历史记录 [rootcloud ~]# vim /etc/profile HISTSIZE1000(默认保存1000条历史记…...

AI 设计工具合集
🐣个人主页 可惜已不在 🐤这篇在这个专栏AI_可惜已不在的博客-CSDN博客 🐥有用的话就留下一个三连吧😼 前言: AI 视频,科技与艺术的精彩融合。它借助先进的人工智能技术,为影像创作带来全新可能。本书…...
mac 源代码安装openresty
1. clone源代码 git clone https://github.com/openresty/openresty.git 2. 安装依赖包 brew install hg unix2dos brew install pcre openssl 3. 编译 make 4. 安装openresty cd openresty-1.27.1.1 ./configure --prefix/opt/openresty --with-http_ssl_module --with-…...

人工智能和机器学习之线性代数(二)
人工智能和机器学习之线性代数(二) 本文Linear Algebra 101 for AI/ML – Part 2将通过介绍向量的点积(dot Product)、Embedding及其在相似性搜索中的应用来建立这些基础知识。 将学习Embedding,Embedding是表示概念、对象和想法的特殊类型的向量。Embedding在整个…...
Postman中的form-data 和 JSON 的区别
在使用 Postman 进行 API 测试时,form-data 和 JSON 是两种常用的请求体格式,它们有以下几个主要区别: 1. 数据格式 form-data: 主要用于表单数据的提交,适合文件上传和键值对的数据传递。数据以键值对的形式编码,类似…...

网络安全基础知识点_网络安全知识基础知识篇
文章目录 一、网络安全概述1.1 定义1.2 信息安全特性1.3 网络安全的威胁1.4 网络安全的特征 二、入侵方式2.1 黑客2.1.1 入侵方法2.1.2 系统的威胁2.2 IP欺骗与防范2.2.1 TCP等IP欺骗基础知识2.2.2 IP欺骗可行的原因2.2.3 IP欺骗过程2.2.4 IP欺骗原理2.2.5 IP欺骗防范2.3 Sniff…...
Vue.js 从入门到精通:全面解析组件化、路由与状态管理(附 Todo 案例)
在当今的前端开发领域,Vue.js 以其简洁、高效和灵活的特点受到了广泛的关注和应用。本文将带你从 Vue 的基础知识入手,逐步深入到高级特性,让你对 Vue 有一个全面的了解,并通过实际案例帮助你更好地掌握 Vue 的开发。 一、Vue 简…...

AI Weekly#1:过去一周重要的AI资讯汇总
🚀热点头条 诺贝尔奖青睐AI领域:2024年诺贝尔物理学奖和化学奖均授予了与人工智能相关的研究。物理学奖颁发给了约翰霍普菲尔德和杰弗里辛顿,表彰他们在机器学习领域的开创性工作。化学奖则授予了大卫贝克、德米斯哈萨比斯和约翰江珀…...
图论刷题
卡码网 98. 所有可达路径 使用邻接矩阵存储: #include<iostream> #include<vector> using namespace std;vector<vector<int>>res;//收集符合条件的路径vector<int>path;//0节点到终点的路径//确定递归函数 参数和返回值void dfs(c…...
ICM20948 DMP代码详解(85)
接前一篇文章:ICM20948 DMP代码详解(84) 上一回解析了inv_icm20948_ctrl_enable_sensor函数的大部分代码,只剩下一行代码没有解析。为了便于理解和回顾,再次贴出inv_icm20948_ctrl_enable_sensor函数源码,在EMD-Core\sources\Invn\Devices\Drivers\ICM20948\Icm20948Data…...
【Java学习笔记】Arrays类
Arrays 类 1. 导入包:import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序(自然排序和定制排序)Arrays.binarySearch()通过二分搜索法进行查找(前提:数组是…...

23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...

React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
三体问题详解
从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解…...

【JavaWeb】Docker项目部署
引言 之前学习了Linux操作系统的常见命令,在Linux上安装软件,以及如何在Linux上部署一个单体项目,大多数同学都会有相同的感受,那就是麻烦。 核心体现在三点: 命令太多了,记不住 软件安装包名字复杂&…...

分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...