1.引言
C++ STL(Standard Template Library)作为C++标准库的核心部分,其重要性不言而喻。它提供了一系列高效、灵活且可复用的数据结构和算法,极大地提升了开发效率,并使得代码更加易于阅读和维护。
在STL中,string容器是一个至关重要的组成部分,它专为处理字符串而设计,提供了丰富的字符串操作功能。
遍历string容器是处理字符串时的基本需求,它允许我们逐一访问和操作字符串中的每个字符,支持复杂的字符串分析任务,并可通过选择合适的遍历方法来优化程序性能。
2.string容器的基本特性
2.1string的定义与初始化
常用的实例化string 对象方式
//默认构造
string s1;
//带参构造
string s2("hello world");
//隐示类型转换
string s3="hello world";
//拷贝构造
string s4 = s1;//与string s4(s1);等价
3.遍历string容器的常用方法
3.1使用下标访问遍历
(1)代码示例:
//下标+[]
for (int i = 0; i < s1.size(); i++)
{
cout << s1[i] << " ";
}
cout << endl;
(2)补充:size()函数是计算字符串长度的成员函数
(3)使用下标遍历实际是调用了运算符重载函数operator[]
函数原型
3.2使用std::string的成员函数at遍历
和下标遍历的方式相似但它允许通过索引访问字符串中的字符,同时提供边界检查。如果试图访问一个超出字符串范围的索引,at函数会抛出一个std::out_of_range异常。
(1)函数原型
(2)代码示例:
// at函数遍历
for (int i = 0; i < s1.size(); i++)
{
cout<<s1.at(i)<<" ";
}
cout << endl;
3.3使用迭代器遍历
在C++中,迭代器是一种用于遍历容器(如std::string)的对象。迭代器提供了对容器元素的访问,并且可以用于读取或修改容器中的元素。使用迭代器遍历std::string时,你可以通过迭代器访问字符串中的每个字符。
(1)代码示例
//迭代器
string::iterator it = s1.begin();
while (it != s1.end())
{
cout << *it << " ";
++it;
}
cout << endl;
string::const_iterator it1 = s2.begin();
while (it1 != s2.end())
{
cout << *it << endl;
++it;
}
cout << endl;
在示例中声明了一个string::iterator类型的迭代器it和一个string::const_iterator类型it1(区别稍后细说)在这里可简单将it和it1看做指针
并将it初始化为s1.begin(),使用循环遍历字符串,直到it!=s1.end();
s1.begin()指向字符串的初始位置(第一个字符的位置),s1.end()指向字符串最后一个位置的下一个位置
(2)函数原型
(3)位置示意图
(4)string::iterator和string::const_iterator的区别
主要体现在对字符串元素的修改权限上:
string::iterator:允许通过迭代器修改字符串中的元素。
string::const_iterator:不允许通过迭代器修改字符串中的元素,只能用于访问。
类比指针可以帮助理解
3.4使用范围基于的for循环遍历(C++11及之后版本)
底层实际使用的是迭代器
//范围for
for (auto& ch : s1)//自动取s1里面的字符自动++
{
cout << ch << " ";
}
3.5使用std::for_each算法遍历
用std::for_each算法遍历std::string时,可以传递一个lambda表达式或者函数对象作为操作,该函数将对字符串中的每个字符执行操作。std::for_each算法接受两个迭代器参数,分别指向要遍历的范围的开始和结束(左闭右开),以及一个函数参数,该函数将对范围内的每个元素执行。
(1)函数原型
template<class InputIterator, class Function>
Function for_each(InputIterator first, InputIterator last, Function f);
这里,first和last是定义要遍历范围的迭代器,f是对每个元素执行的函数。
(2)下面是一个使用std::for_each算法遍历std::string的示例代码:
#include <iostream>
#include <string>
#include <algorithm>
int main() {
std::string str = "Hello, World!";
// 使用 std::for_each 遍历字符串
std::for_each(str.begin(), str.end(), [](char c) {
std::cout << c << ' ';
});
std::cout << std::endl;
return 0;
}
在这个示例中,std::for_each接受三个参数:str.begin()和str.end()是std::string的迭代器,它们定义了要遍历的范围;第三个参数是一个lambda表达式,它接受一个char类型的参数并打印它。这个lambda表达式将对字符串中的每个字符执行。
(3)补充:
lambda表达式是一种匿名函数,它允许快速定义单行的小函数,通常用于需要函数对象的地方。
lambda表达式的语法结构在C++中相对简单明了。它通常遵循以下格式:
[ capture ] ( parameters ) -> return_type {
// 函数体
}
然而,并非所有部分都是必需的。在很多常见情况下,lambda表达式可以被大幅简化。例如,当不需要捕获任何外部变量,且函数体较为简短时,可以省略捕获列表和返回类型,甚至参数列表也可以省略(这种情况下,lambda表达式将没有参数)。
一个最基本的lambda表达式,不接受参数且不执行任何操作,可以是这样:
[]() { };
若需要向lambda表达式传递参数,并希望其返回特定类型的值,可以如此定义:
[](int x, int y) -> int {
return x + y;
};
在C++11及之后的版本中,如果lambda表达式的函数体仅包含一个return语句,且此语句用于返回某个表达式的值,那么可以进一步简化,省略return关键字及花括号:
[](int x, int y) -> int { return x + y; }
// 可简化为
[](int x, int y) -> int { x + y }
// 在C++11及以后版本中,甚至可以进一步简化为
[](int x, int y) { return x + y; }
// 或
[](int x, int y) { x + y }
最后,如果lambda表达式的返回类型可以被编译器明确推断出来,那么返回类型也可以省略:
[](int x, int y) { return x + y; }
欢迎各位大佬一起学习交流~