inititle 网站建设,微信官方服务平台,网站开发的配置过程,在哪个网站上做实验仪器比较好但是在讲解它之前#xff0c;我们需要先了解迭代的对象是什么。常见的一种#xff0c;叫做 vector。vector 类型使用可变有序序列我们知道#xff0c;数学里#xff0c;vector 是向量的意思。但 C 里的向量和它不太一样。它的含义是#xff0c;具有可变元素个数的有序对象…但是在讲解它之前我们需要先了解迭代的对象是什么。常见的一种叫做 vector。vector 类型使用可变有序序列我们知道数学里vector 是向量的意思。但 C 里的向量和它不太一样。它的含义是具有可变元素个数的有序对象序列。之所以这里说的是对象序列是因为 vector 可以存储任意类型的对象我们通常称之为泛型即广泛的类型。#include vector //先引入一下vectorint v;vectorstring v2;vectordouble v3;看看上面的代码这下看懂了。先声明 vector再用尖括号包裹 vector 存储的数据类型。OK 现在我们有了空的对象序列。是时候向其中存入元素了。int i 10;v.push_back(i);使用 .push_back()允许我们向对象序列的末尾加入元素。由于它是可变长度的所以可以随意加入对象。有一点需要注意vector 永远不会存储引用。也就是说它会创建圆括号中的对象的拷贝或者移动该对象。你应该已经了解过 string 或者 数组 了。与它们类似我们也可以用下标运算符来获取其中某个元素的引用注意下标从 0 开始且你不能超过已有元素的范围。比如v.push_back(i);...v[5] 10; // 修改第 6 个元素要想知道一共有多少元素避免超出可以用 size()。不过它返回的是 size_type你可以用 auto 自动判断类型。auto vsize v.size(); // 自动判断返回值类型初始化问题我们之前都是先创建空的 vector然后再装入对象。实际上我们也可以直接初始化 vector。vectorint v1{1, 2}; // 1,2vectorint v2(2); // 0,0vectorint v3(2,3); // 3,3如上初始化有花括号列表初始化和圆括号值初始化两种方式。如果是花括号那么其中的对象列表就会被加入到 vector 中。比如第一行就初始化了一个包含 2 个数字的 vector。而如果是圆括号那么分两种情况如果只输入一个值那么它会创建相应大小 vector然后初始化所有值为对应对象的默认值对于 int这是 0如果输入两个值那么会把第二个值复制并根据第一个值确定元素个数填充入 vector。比如第三行2 个 3。注意初始化只是创建空白 vector 然后存入并非固定了大小。也就是说你还可以继续使用 push_back() 加入元素来扩展其大小。其实还有个特殊情况。如果花括号内的数据无法用于初始化一个 vector那么它会自动作为圆括号处理vectorstring v{2}; // ,vectorstring v1{2,HELLO}; // HELLO,HELLO第一行创建了含有 2 个初始值的 string 对象的 vector第二行则创建了含有 2 个 HELLO 的 string 对象的 vector。实际上如果你不需要快速创建多个相同的元素你没有任何理由去用初始化。你可以创建空的 vector然后随意动态添加元素。还有一点需要注意。可以直接把一个 vector 复制到另一个vectorint v2;v2 v1; //OK迭代器好了既然我们已经有了一个对象的集合让我们进入正题吧。vectorint v1 {1,2,3,4,5};for(auto it v1.begin();it!v1.end();it){cout*itendl;}// 输出一行一个 v1 中的元素等等等上面的代码有些复杂我们一点点解释顺便说明什么是迭代器。第一行创建了一个含有 5 个元素的 vector。然后用了一个 for 语句——什么是迭代器首先是初始化auto it v1.begin();这就是我们的主角迭代器。我们用了自动类型判断实际上 it 的类型是vectorint::iterator也就是说vector 有一个迭代器而 vector 其中存储的对象是 int 类型的。嗯你应该能推测出来v1.begin() 返回的是一个迭代器类型。顾名思义它返回的是指向第一个对象的迭代器。你或许注意到了指向这个词我们在指针那里曾经提到过。比较相似迭代器也是“一次指向一个对象”只不过该对象必须存在于一个 vector 中。什么意思呢你可以理解为迭代器是和一组对象结合使用的“指针”在一个时刻指向其中的一个对象。比如上面那行就创建了指向第一个对象 1 的迭代器。那么这样有什么好处呢我们先来看 for 的第三部分。it;居然对一个迭代器用了自增运算符这就是迭代器和指针的区别了——由于它指向一组对象所以可以随意调整让它指向其它对象只要目标对象存在于组内。我们之前提到vector 是有序的所以才能使用下标运算符。而正是这种有序性使自增自减成为可能。如果增加迭代器就是让它指向当前对象之后的元素如果减少迭代器就是让它指向当前对象之前的元素。看看下面的例子vectorint v {233,234,114,432,534};auto it v.begin(); // index 0,*it 233it; // index 1,*it 234it 2; //index 3,*it 432it - 3; //index 0,*it 233index 表示当前指向对象的下标。*it 表示指向对象的值。先不用管那个星号我们下面会涉及。好的第二部分it ! v1.end();条件判断用的是不等号。v1.end() 返回的是指向 vector 列表最后一个元素的下一地址的迭代器。之所以不使用比较符号是因为并不是所有迭代器都可以比较但是它们都支持不等号/等号使用不等号更加通用。也就是说它并不指向任何元素但是如果你有一个指向最后一个元素的迭代器那么再加一就指向该位置。回忆一下 for 的使用方法。当这个不等号条件不满足时大括号内的语句不会被执行。即当完成最后一个元素的处理后在这个例子里输出了 5 这个数条件判断为假循环结束。综上上面代码的输出是12345也就是说这样编写代码允许我们遍历序列中的所有元素而不会漏掉最后一个。注意任何使用迭代器的场景都不能涉及更改序列大小否则迭代器会失效。这是因为vector 大小是动态扩展的更改大小可能会自动移动位置来保证充足内存空间导致迭代器指向的序列失效算术运算实际上我们可以计算指向同一序列的两个迭代器的差值vectorint v(10);auto it v.begin();auto it2 v.end();coutit2-itendl; // output: 10输出结果是 10。可视化一下实际上是这样的数字表示下标iterator解引用你或许注意到了我们在上面的代码和注释里里用了同样在指针那一节介绍的 * 解引用符。这是因为迭代器也和指针一样指向一个位置用解引用符可以获取位置对应的对象。但是等等。如果你好奇心比较旺盛可能会尝试这个coutitendl; // Errorcout*itendl;你看我不解引用不就能看看迭代器指向对象的地址了吗然而现实是这个第一行无法通过编译。为什么因为迭代器不是指针而是一个其它的类型。它只是和指针很像罢了。你可以认为它指向一个地址从而可以使用解引用运算符但是你不能把它直接当作指针来用。当然既然解引用得到的是一个对象那么当然可以做许多事情比如调用函数。但是要小心注意优先级你应该先解引用再调用函数vectorstring v{Hello,World};auto it v.begin();cout (*it).substr(2) endl; // output: llocout *it.substr(2) endl; // Error范围 for 语句上面我们用三个元素的 for 语句进行了遍历的操作其实我们可以简化。vectorint v{1,2,3,4};for(auto i:v){coutiendl;}这个语句叫做范围 for 语句。它会一个一个取出序列中的元素。和迭代器不同它返回对象并拷贝赋值给冒号前的变量这里是 i而非其本身。即修改 i 时不会修改 v 序列中的任何内容。如果你想修改可以把变量创建为引用vectorint v{1,2,3,4};for(auto i:v){i 3;}for(auto i:v){coutiendl;}// 3 3 3 3如果你不想改但不想拷贝防止性能损耗可以创建常量引用。for(const auto i:v){coutiendl;// 禁止修改。}不止 vector我们一直在探讨 vector但实际上迭代器对于其它的序列也能使用比如 string。你可以在使用的时候去查一下是否实现了迭代器。写法都一样这里省略。那么范围 for 呢实际上实现了 begin 和 end 的类型都是可以使用的满足以下条件即可begin,end 返回的是一个迭代器迭代器可以自增也就是说范围 for 只是一种缩写只要能用迭代器就能用。在遍历时推荐使用可以使代码更易读。好了这就是 vector 和迭代器的全部内容我们下次再继续拆解 C奶奶级。