深度剖析C++string(上篇)(2):https://developer.aliyun.com/article/1624968
4.. string类对象的访问及遍历操作
【】既可以访问字符又可以修改字符,非常的方便。
void string3() { string s1("I love you"); // 获取begin和end迭代器 std::string::iterator it = s1.begin(); std::string::iterator it_end = s1.end(); cout << s1[3] << endl; s1[1] = 'u'; cout << s1 << endl; cout << *it << endl; // 输出 I,因为it指向第一个字符 cout << *(it_end-1) << endl; }
上面是正向迭代器的使用,还有一个反向迭代器
std::string::reverse_iterator it = s1.rbegin(); std::string::reverse_iterator it_end = s1.rend();
接下来我们通过迭代器来实现字符串的遍历
void string4() { string s("I love you!"); // 获取begin和end迭代器 string::iterator it = s.begin(); string::reverse_iterator it1 = s.rbegin(); while (it != s.end()) { cout << *it << " " ; ++it; } cout << '\n'; while (it1 != s.rend()) { cout << *it1 << " " ; ++it1; // 移动到下一个字符(实际上是前一个字符) } }
C++11之后,直接使用auto定义迭代器,让编译器推到迭代器的类型
void string4() { string s("I love you!"); // 获取begin和end迭代器 //string::iterator it = s.begin(); auto it = s.begin(); //string::reverse_iterator it1 = s.rbegin(); auto it1 = s.rbegin(); while (it != s.end()) { cout << *it << " " ; ++it; } cout << '\n'; while (it1 != s.rend()) { cout << *it1 << " " ; ++it1; // 移动到下一个字符(实际上是前一个字符) } }
范围for
for (auto ch : s){ cout << ch << endl; }
5. auto和范围for(补充)
auto关键字
在这里补充2个C++11的小语法。
在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量,后来这个 不重要了。C++11中,标准委员会变废为宝赋予了auto全新的含义即:auto不再是一个存储类型 指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期 推导而得。
用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&
当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际 只对第一个类型进行推导,然后用推导出来的类型定义其他变量。
auto不能作为函数的参数,可以做返回值,但是建议谨慎使用
auto不能直接用来声明数组
// 编译报错:error C3538: 在声明符列表中,“auto”必须始终推导为同一类型
auto cc = 3, dd = 4.0;
// 编译报错:error C3318: “auto []”: 数组不能具有其中包含“auto”的元素类型
auto array[] = { 4, 5, 6 };
#include <iostream> using namespace std; int func1() { return 10; } // 不能做参数 void func2(auto a) {} // 可以做返回值,但是建议谨慎使用 auto func3() { return 3; } int main() { return 0; }
#include <iostream> using namespace std; int func1() { return 10; } int main() { int a = 10; auto b = a; auto c = 'a'; auto d = func1(); // 编译报错:rror C3531: “e”: 类型包含“auto”的符号必须具有初始值设定项 //auto e; cout << typeid(b).name() << endl; cout << typeid(c).name() << endl; cout << typeid(d).name() << endl; int x = 10; auto y = &x; auto* z = &x; auto& m = x; cout << typeid(x).name() << endl; cout << typeid(y).name() << endl; cout << typeid(z).name() << endl; return 0; }
其实对于auto的真正常用的用法是用于迭代器方面,让编译器自己推导迭代器类型,对于复杂的迭代器类型可以简化代码。
下面展示的代码为扩展,别处拷贝过来。
#include<iostream> #include <string> #include <map> using namespace std; int main() { std::map<std::string, std::string> dict = { { "apple", "苹果" },{ "orange", "橙子" }, {"pear","梨"} }; // auto的用武之地 //std::map<std::string, std::string>::iterator it = dict.begin(); auto it = dict.begin(); while (it != dict.end()) { cout << it->first << ":" << it->second << endl; ++it; } return 0; }
std::map<std::string, std::string> dict = { { "apple", "苹果" },{ "orange", "橙子" }, {"pear","梨"} };
:定义一个std::map
对象dict
,它包含三个键值对,键是std::string
类型的字符串,值也是std::string
类型的字符串。
范围for
对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此 C++11中引入了基于范围的for循环。
for循环后的括号由冒号“ :”分为两部分:第一部分是范围 内用于迭代的变量,第二部分则表示被迭代的范围,自动迭代,自动取数据,自动判断结束。
范围for可以作用到数组和容器对象上进行遍历
范围for的底层很简单,容器遍历实际就是替换为迭代器,这个从汇编层也可以看到。
#include <iostream> #include <string> using namespace std; int main() { int arr[] = { 1,2,3,4,5 }; for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) { arr[i] *= 2; } for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) { cout << arr[i] << endl; } // C++11的遍历 for (auto &e : arr) { e *= 2; } for (auto e : arr) { cout << e << endl; } string s("hello world!"); for (auto it : s) { cout << it << " " ; } return 0; }
结束语
本期讲解就到此结束了,下节我们将继续扩展string的其他接口和函数。
最后感谢各位友友的支持,友友们点个赞吧!!!