IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 【手把手入门C++】第六章:STL之快速上手使用vector及迭代器失效问题 -> 正文阅读

[C++知识库]【手把手入门C++】第六章:STL之快速上手使用vector及迭代器失效问题


适合人群
如果你想要快速上手使用vector接口,将常用接口看完并且全部试验一遍即可。
如果想要了解迭代器失效的概念,可以试验一下最后两个小案例。

1、认识vector

1.1.vector简介

  • vector是向量类型,可以容纳许多类型的数据,因此也被称为容器
  • 可以理解为动态数组,是封装好了的类
  • 进行vector操作前应添加头文件#include<vector>

这只是vector的剪短介绍,如果还想深入了解vector的小伙伴可以参考vector官方文档

2、vector的常用接口

2.1.一维vector初始化

方式1:

// 定义具有5个int类型元素的向量(<>中可以是任意的数据类型)
// 不具有初值(在新的编译器中默认会初始化尾0)
vector<int> v(5);

方式2.

// 定义具有5个int类型元素的向量,并且每一个元素初值为1
vector<int> v(5, 1);

方式3.

// 用向量v2赋值给向量v1,使v2中元素的值和v1中元素的值完全相等
vector<int> v1(v2);// 当可以相当于v1 = v2使用 

方式4.

// 利用迭代器将向量v2赋值给向量v1,使v2中元素的值和v1中元素的值完全相等
vector<int> v1(v2.begin(), v2.end());

// 将向量v2中0~4号int类型元素(一共使5个元素)赋值给向量v1
// 拷贝区间为[v2.begin(), v2.begin()+5),左闭右开
vector<int> v1(v2.begin(), v2.begin()+5);

方式5.

// 用数组初始化向量v
// 拷贝区间为[arr, arr + 5),左闭右开
int arr[5] = {1, 2, 3, 4, 5};
vector<int> v(arr, arr + 5);

2.2.二维vector初始化

// 定义一个行可以扩展,列可以扩展的二维数组
vector<vector<int>> v;
// 定义一个有10行,列可以扩展的二维数组
vector<vector<int>> v(10)
// 定义一个有10行,有20列,并且所有元素都初始化为1的二维数
vector<vector<int>> v(10, vector<int>(20, 1));

2.3.对vector进行操作(举例说明)

头文件

// 假设已经定义好了两个向量
#include <vector>
vector<int> v1, v2;

// 将向量v2中复制给向量v1
v1.assign(v2.begin(), v2.end());
// v1中有10个值为5的元素
v1.assign(10, 5);

// 在向量v1的尾部插入一个值为10的元素
v1.push_back(10);
// 在向量v1的尾部插入一个值为10的元素
v1.emplace_back(10);
// 在向量v1的第一个元素位置(第一个位置是第0个元素)插入数值10
v1.emplace(v1.begin() + 1, 10);

// 在向量v1的第一个元素位置(第一个位置是第0个元素)插入数值3
v1.insert(v1.begin() + 1, 3);
// 在向量v1的第一个元素位置(第一个位置是第0个元素)插入10个数值3
v1.insert(v1.begin() + 1, 10, 3);
// 在向量v1的第一个元素位置(第一个位置是第0个元素)插入v2的第5个元素发到第9个元素
v1.insert(v1.begin() + 1, v2.begin() + 5, v2.begin() + 10);

// 删除向量v1中最后一个元素
v1.pop_back();
// 删除向量v1的第二个元素位置(第一个位置是第0个元素)上的元素
v1.erase(v1.begin() + 2);
// 删除向量v1的第一个元素位置(第一个位置是第0个元素)到第四个元素位置(不是第5个元素)内的元素
v1.erase(v1.begin() + 1, v1.begin() + 5);
// 清空向量v1中的元素
v1.clear();

// 注意vector中没有find()函数!
// 注意vector中没有find()函数!
// 注意vector中没有find()函数!

// 访问向量v1的第i个元素(如果v1有第i个元素的话),如果数组越界不会处理
v1[i];
// 访问向量v1的第i个元素(如果v1有第i个元素的话),如果数组越界会抛异常
v1.at(i)
// 返回向量v1的第一个元素
v1.front();
// 返回向量v1的最后一个元素
v1.back();
// 返回向量v1中元素的个数
v1.size();
// 返回向量v1当前可以容纳的元素个数
v1.capacity();
// 判断向量v1是否为空
v1.empty();

// 将现在的元素个数调整为10个,元素多出就删掉,元素不够就默认补0
v1.resize(10);
// 将现在的元素个数调整为10个,元素多出就删掉,元素不够就2
v1.resize(10, 2);
// 将向量v1的容量改为100
v1.reverse(100);
// 交换向量v1和v2
v1.swap(v2);

3、访问vector的几种方式

3.1.对向量添加元素

1.向向量中添加元素

vector<int> v;
for (int i = 0; i < 10; i ++) {
	v.push_back(i);
}

2.从数组中选取数字添加到向量中

int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
vector<int> v;
for (int i = 5; i < 10; i ++) {
	v.push_back(a[i]);
}

3.从一个向量中选取元素添加到另一个向量中

vector<int> v1 = {1, 2, 3, 4, 5};
vector<int> v2;
for (vector<int>::iterator it = v1.begin(); it != v1.end(); it ++) {
	v2.push_back(*it);
}

4.错误的添加方式

// 只有当存在元素的时候才可以用下标访问元素,在定义的时候v中还没有元素。
vector<int> v;
for (int i = 0; i < 10; i ++) {
	v[i] = i;
}

3.2.从向量中读取元素

1.通过下标获取元素

vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (int i = 0; i < v.size(); i ++) {
	cout << v[i] << ' ';
}

2.通过迭代器获取元素

vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (vector<int>::iterator it = v.begin(); it != v.end(); it ++) {
	cout << *it << ' ';
}

3.范围for遍历元素

vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (int num : v) {
	cout << num << ' ';
}	

4、常用的几种配合vector的算法

#inlude <algorithm>
// 将向量中从v.begin()到v.end()前一个位置(不包括v.end())中的数进行排序
sort(v.begin(), v.end();
// 从向量v中从v.begin()到v.end()前一个位置(不包括v.end())内找数值2
find(v.begin(), v.end(), 2);
// 将向量v中从v.begin()到v.end()前一个位置(不包括v.end())中的数翻转
reverse(v.begin(), v.end());
// 比较v[0]和v[1]的最大值
max(v[0], v[1]);
// 比较v[0]和v[1]的最小值
min(v[0], v[1]);


5、迭代器失效

先将结论在举例子。

迭代器失效两种情况:
1.迭代器iterator所指向的空间已经被释放,对于vector这样的序列容器来说,此时iterator已经是野指针了。
2.迭代器iterator的代表的意义改变了。

如果你不懂上面的两种情况也没事,在看完下面的例子时候,再回头看一遍就懂了。

1.iterator变成"野指针"

vector<int> v = { 1, 2, 3, 4, 5 };
vector<int>::iterator it = v.begin();
cout << *it << endl;// 输出1

// 将向量v扩容至10个元素
v.reserve(10);
cout << *it << endl;// 程序崩溃

因为it = v.begin(),所以当*it的时候,输出的应该是1。但是在扩容之后,*it就不能再输出了。这就是迭代器失效导致的。
解释:我们要有一个前置只是就是在vector扩容的时候,并不是直接在容器的后面再开一段连续的空间,而是先拷贝一份更大的空间,然后讲原空间的vector中的元素一个一个的拷贝到先开的空间当中,最后释放掉原空间。虽然空间的数值都被拷贝到新空间中,但是原来的迭代器还在指向原有空间的开头位置,这就是迭代器失效。
在这里插入图片描述
所以只要当vector发生扩容的时候就会发生这种迭代器失效,所以平时使用insertpush_back()的时候都要小心。

2.iterator的意义改变了

vector<int> v = { 2, 4, 5 };

vector<int>::iterator it = v.begin();
while (it != v.end()) {
	if (*it % 2 == 0) v.erase(it);// 如果*it为偶数就删掉    
	it++;// 迭代器往后走一步    
}

for (int i = 0; i < v.size(); i++) {
	cout << v[i] << ' ';// 输出4,5
}

为什么输出了4和5呢?(在Linux平台上输出4,5,在vs平台上直接程序崩溃)。
解释:因为2是偶数,所以一上来就要erase掉2,然后iterator往后走一步指向4。等等在这一步的时候就已经错了,iterator不指向4,而是指向5。???为什么呢?因为vector是序列式容器,在erase之后所有在iterator之后的元素都会往前移动一位,这样覆盖掉了原来iterator指向的位置了
在这里插入图片描述
所以,如果要改正这个错误的话,就要保证当删除元素的时候,迭代器it就不能往后走了,只有当没有删除元素的时候,迭代器才可以往后走。

vector<int> v = { 2, 4, 5 };

vector<int>::iterator it = v.begin();
while (it != v.end()) {
	if (*it % 2 == 0) it = v.erase(it);// 更新一下it指向的位置
	else it++;// 迭代器往后走一步    
}

for (int i = 0; i < v.size(); i++) {
	cout << v[i] << ' ';// 输出4,5
}

在erase数值之后,我们以为迭代器指向的位置,却不是它的位置,这种就是迭代器的意义改变了。也就是第二中迭代器失效。

总结:迭代器失效的两种情况
1.当insert或者erase的时候,因为iterator不会随着指向元素的改变(增加或者删除)而改变,单只iterator的意义发生改变。
2.当insert或者erase的时候,导致容器扩容或者缩容时,iterator变成了"野指针"。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-31 16:26:28  更:2021-07-31 16:27:06 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年4日历 -2024/4/27 13:50:47-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码