string类对象的访问及遍历操作
3、string类对象的访问及遍历操作
函数名称 | 功能说明 |
---|---|
operator[] —— 重点 | 返回 pos 位置的字符,const string 类对象调用 |
begin + end | begin 获取一个字符的迭代器,end 获取最后一个字符下一个位置的迭代器 |
rbegin + rend | begin 获取一个字符的迭代器,end 获取最后一个字符下一个位置的迭代器 |
范围 for | C++11 支持更简洁的范围 for 的新遍历方式 |
#include<assert.h>
#include<string>
#include<iostream>
using namespace std;
//大概原理
template<class T>
class basic_string
{
public:
char& operator[](size_t pos)
{
assert(pos < _size);//检查越界:s2[20] -> err
return _arr[pos];
}
private:
T* _arr;
int _size;
int _capacity;
};
//typedef basic_string<char> string;
int main()
{
//逐一遍历字符串
//1、operator[]
string s1("hello world");
for(size_t i = 0; i < s1.size(); ++i)
{
s1[i] += 1;//写
}
for(size_t i = 0; i < s1.size(); ++i)
{
cout << s1[i] << " ";//读
}
cout << endl;
//2、范围for
string s2("hello world");
for(auto& e : s2)
{
e += 1;//写
}
for(auto e : s2)
{
cout << e << " ";//读
}
cout << endl;
//3、迭代器
string s3("hello world");
string::iterator it = s3.begin();
while(it != s3.end())
{
*it += 1;//写
++it;
}
it = s3.begin();
while(it != s3.end())
{
cout << *it << " ";//读
++it;
}
cout << endl;
return 0;
}
📝说明
operator [] | at ❗
operator[] 和 at 的价值是一样的,但是不一样的地方是对于越界:operator[] 直接使用断言报错,比较粗暴;而 at 则会抛异常。
范围 for ❗
这是 C++11 中提出的新语法,比较抽象,对于它的原理,后面会再模拟实现它。
注意 auto e : s3 只能读,不能写;auto& e : s3 可读可写。
迭代器 ❗
它是 STL 中六大组件中的核心组件,这里先见个面。
begin() 返回第一个有效数据位置的迭代器;
end() 返回最后一个有效数据的下一个位置的迭代器;
目前可以认为它类似于指针,—— 有可能是指针,有可能不是指针,因为不仅仅 string 有迭代器,其它容器里也有迭代器。
while(it != s3.end()) 也可以 while(it < s3.end()),但不建议。这里是数组,换成小于它依然没问题,但是如果是链表,小于就不行了。所以这里统一就用不等于。
迭代器的好处是可以用统一类似的方式去访问修改容器 (也就意味着会了 string 的迭代器就等于会了其它容器的迭代器):
为什么这里要提供三种遍历方式 ❓
其实只提供了两种,因为范围 for 本质是迭代器,也就是说一个容器支持迭代器才会支持范围 for,后面会演示。
operator [] 可以像数组一样去访问,这种方式对于 vector 连续的数据结构是支持的,但是不支持 list。
迭代器这种方式是任何容器都支持的方式,所以迭代器才是容器通用的访问方式。
再简单了解迭代器 ❗
#include<string>
#include<iostream>
using namespace std;
void Print1(const string& s)//不需要写
{
string::iterator it = s.begin();//err,普通迭代器
//string::const_iterator it = s.begin();//ok,const迭代器
//string::const_iterator it = s.cbegin();//ok,C++11提供的cbegin
while(it != s.end())
{
cout << *it << " ";
++it;
}
cout << endl;
}
void Print2(const string& s)
{
string::reverse_iterator rit = s.rbegin();//err,普通反向迭代器
//string::const_reverse_iterator rit = s.rbegin();//ok,const反向迭代器
//auto rit = s.rbegin();//ok,auto的体现
while(rit != s.rend())
{
cout << *rit << " ";
++rit;//注意这里不是--
}
cout << endl;
}
void test_string()
{
string s1("hello");
Print1(s1);
string s2("hello");
Print2(s2);
}
int main()
{
test_string();
return 0;
}
📝说明
这里利用迭代器打印 s1:
查文档:begin 有两个版本
所以报错的原因是:s 是 const 对象,返回的是 const 迭代器,而这里使用普通迭代器来接收。解决方法就是用 const 迭代器接收。
在文档中看到 C++11 中又提供了一个 cbegin ???
为什么 C++11 把 const 迭代器单独拎出来,大概原因应该是 begin 里有普通 / const 迭代器不太明确,容易误导。不知道大家是怎么想的,我是觉得有点画蛇添足了。
rbegin:
rbegin 就是反向迭代器,顾名思义就是反向遍历。
auto 的价值 ❗
到了迭代器这里我们就可以用 auto 来替代比较长的类型,auto 的价值得以体现。
- 点赞
- 收藏
- 关注作者
评论(0)