在使用vector容器或者字符串时,很经常会用到一些遍历操作,除了使用下标遍历之外,使用迭代器遍历也是超级方便,但是迭代器也有有一些小坑,一不注意就会编译出错,所以特意总结一下。
迭代器
迭代器很很多接口,不过最重要要搞清楚迭代器指向的位置!!
str.begin();指向字符串的第一个字符的位置
str.end();指向字符串的最后一个字符的后一个位置;
str.rbegin();指向字符串的最后一个字符的位置;
str.rend();指向第一个字符串的前一个位置;
举个例子:
使用迭代器遍历
迭代器的使用方式和指针类似
设计规范:
1.begin迭代器:指向第一个元素的位置;
2.end迭代器:指向最后一个元素的末尾;
3.访问数据:通过解引用完成:*,->
4.迭代器移动:++移动到下一个元素的位置,移动到上一个元素的位置;
5.位置的判断:支持!=,==
有些容器具有反向迭代器
6.rbegin迭代器:指向最后一个元素的位置;
7.rend迭代器:指向第一个元素的前一个位置
依然举个例子:
// iterator begin(); const_iterator begin() const;
// iterator end(); const_iterator end() const;
void stringTraverse() {
string str1 = "12345";
string::iterator it = str1.begin();
while(it != str1.end()){
cout << *it << " ";
// 可以 *it = 'a';
++it;
}
cout<<endl;
}
这里可能有同学会有疑问,为什么循环的终止条件是iter!=str.end(),但是还能便利字符串里的最后一个字符呢?往前翻一翻,答案一目了然,因为end()指向的最后一个字符串的后一个位置;
还有心细的同学发现,第一张图片中除了有刚刚介绍的四个接口以外,还有4个接口:cbegin,cend,crbegin,crend;有什么区别呢?其实很简单 这些接口的返回类型都是constiterator,也就是只读,不能修改对应的值。
再举个例子:
// iterator begin(); const_iterator begin() const;
// const_iterator cbegin() const
void stringTraverse() {
string str1 = "12345";
string::iterator it = str1.begin();
while(it != str1.end()){
cout << *it << " ";
// 可以 *it = 'a';
++it;
}
}
void stringTraverse() {
const string str3 = "12345";
string::const_iterator it3 = str3.cbegin();
while (it3 != str3.cend()) {
// 不可以 *i = 'a';
cout << *it3 << "";
++it3;
}
cout << end1;
}
使用auto遍历
auto是一个C/C++语言存储类型,仅在语句块内部使用,初始化可为任何表达式,其特点是当执行流程进入该语句块的时候初始化可为任何表达式。简单说就是 auto关键字可以自动给变量一个相应的数据类型,在遍历的时候就特别方便,比如:
void stringTraverse() {
string str1 = "12345";
for(auto iter = str.begin(); iter != str.end(); iter++) {
cout << *iter; //迭代器访问
}
cout<<endl;
}
甚至可以更简单:
void stringTraverse() {
string str1 = "12345";
for(auto iter : str1) {
cout << *iter; //迭代器访问
}
cout<<endl;
}
关于auto的一些碎碎念
规则1:声明为auto(不是auto&)的变量,忽视掉初始化表达式的顶层const。即对有const的普通类型(int
、double等)忽视const,对常量指针(顶层const)变为普通指针,对指向常量(底层const)的常量指针(顶层cosnt)变为指向常量的指针(底层const)。
规则2:声明为auto&的变量,保持初始化表达式的顶层const或volatile 属性。
规则3:若希望auto推导的是顶层const,加上const,即const auto。
个人认为,上述的推导规则,不太容易理解,本人也不太理解,可以参照参考博客中的例子进行理解,对于初学者理解auto来说,主要知道auto用来代替冗长复杂或未知的变量声明即可。
关于string和vector的碎碎念
这里也给大家拓展一下字符串和数组有什么差别,
字符串是若干字符组成的有限序列,也可以理解为是一个字符数组,但是很多语言对字符串做了特殊的规定,接下来我来说一说C/C++中的字符串。
在C语言中,把一个字符串存入一个数组时,也把结束符 '\0’存入数组,并以此作为该字符串是否结束的标志。
例如这段代码:
char a[5] = "asd";
for (int i = 0; a[i] != '\0'; i++) {
}
在C++中,提供一个string类,string类会提供 size接口,可以用来判断string类字符串是否结束,就不用’\0’来判断是否结束。
例如这段代码:
string a = "asd";
for (int i = 0; i < a.size(); i++) {
}
那么vector< char > 和 string 又有什么区别呢?
其实在基本操作上没有区别,但是 string提供更多的字符串处理的相关接口,例如string 重载了+,而vector却没有。
所以想处理字符串,我们还是会定义一个string类型。