1. string类介绍
string类是C++标准库中给出的一种类类型,其目的是为了代替C语言中的字符串。
C语言中,字符串是以'\0'结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。
string类通过运算符重载,基本兼容了C语言中字符串的特性,字符串也可隐式类型转换为string类。
在OJ中,有关字符串的题目基本以string类的形式出现,而且在常规工作中,为了简单、方便、 快捷,基本都使用string类,很少有人去使用C库中的字符串操作函数。
2. string类的使用
2.1 string类参考文档
string - C++ Reference
接下来的内容基本都是参考该文档的介绍,进行了相应的总结与拓展。
在使用string类时,必须包含#include<string>以及using namespace std;
2.2 string类的默认成员函数
2.2.1 构造函数
默认构造函数 | string(); |
拷贝构造 | string(const string& str); |
用子串(pos开始,长度为len)拷贝构造 | string(const string& str, size_t pos, size_t len = npos); |
拷贝字符串 | string(const char* s); |
拷贝字符串前n个元素 | string(const char* s, size_t n); |
用字符c填充前n个元素 | string(size_t n, char c); |
npos是string类的静态成员变量,值为类型为size_t,值为整形最大值。
2.2.2 析构函数
摧毁string对象,释放其分配到的所有空间。析构函数在对象销毁时自动调用,无需我们过多注意。
2.2.3 赋值运算符重载
用另一个string对象赋值(深拷贝) | string& operator=(const string& str); |
用字符串赋值 | string& operator=(const char* s); |
用字符赋值 | string& operator=(char c); |
2.3 string类的常用成员函数
2.3.1 迭代器相关
迭代器是STL容器的通用迭代访问媒介,包含4类:
正向迭代器 | string::iterator | begin()---end() |
反向迭代器 | string::reverse_iterator | rbegin()---rend() |
const正向迭代器 | string::const_iterator | crbegin()---crend() |
const反向迭代器 | string::const_reverse_iterator | crbegin()---crend() |
四个对应函数分别可以获取四类迭代器。
正向迭代器即正向对字符串访问,反向迭代器即逆向对字符串访问,const修饰的用于const对象。
int main()
{
string s("hello world");
// 正向迭代
string::iterator it = s.begin();
while(it != s.end())
{
cout << *it << " ";
it++;
}
cout << endl;
// 逆向迭代
string::reverse_iterator rit = s.rbegin();
while(rit != s.rend())
{
cout << *rit << " ";
rit++;
}
cout << *rit << endl;
return 0;
}
2.3.2 容量大小相关
string类的对象至少包含size,capacity和str三个成员变量,下面的函数与之有关:
size_t size() const; | 返回字符串有效字符长度 |
size_t length() const; | 返回字符串有效字符长度(与size完全相同) |
size_t capacity() const; | 返回空间总大小 |
bool empty() const; | 检测字符串释放为空串,是返回true,否则返回false |
void clear() const | 清空有效字符 |
void reserve(size_t n = 0); | 为字符串预留空间 |
void resize(size_t n, char c = '\0'); | 将有效字符的个数该成n个,如果size变大,多出的空间用字符c填充 |
注意:
1. size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()。
2. clear()只是将string中有效字符清空,不改变底层空间大小。
3. resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。
注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。
4. reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参小于string的底层空间总大小时,reserver不会改变容量大小。
2.3.3 对象访问即遍历操作
string类对"[]"进行了重载,我们可以像访问字符串一样,使用"[]"对string类的对象的字符元素进行访问。
遍历string的方式有三种:
1. for + []
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s("hello world");
for (int pos = 0; pos < s.size(); pos++)
{
cout << s[pos] << " ";
}
cout << endl;
return 0;
}
2. 迭代器
前面已经对这种遍历方式进行过介绍,此处不再重复
3. 范围for
对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此 C++11中引入了基于范围的for循环。
for循环后的括号由冒号“ :”分为两部分:第一部分是范围 内用于迭代的变量,第二部分则表示被迭代的范围,自动迭代,自动取数据,自动判断结束。
范围for可以作用到数组和容器对象上进行遍历,范围for的底层很简单,容器遍历实际就是替换为迭代器,这个从汇编层也可以看到。
int main()
{
string s("hello world");
for (auto ch : s)
{
cout << ch << " ";
}
cout << endl;
return 0;
}
补充:
auto关键字表示让编译器在编译时自动推导出变量的类型,这里的auto其实在编译时就被替换为了char,因为范围for从s中读取到的数据类型为char。
auto关键字的注意事项:
1. auto声明的变量必须由编译器在编译时期 推导而得。
2. 用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&。
3. 当在同一行用auto声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。
4. auto不能作为函数的参数,可以做返回值,但是建议谨慎使用。
5. auto不能直接用来声明数组。
2.3.4 string类对象的修改操作
void push_back(char c) | string尾部插入单个字符 |
string& append(const string& str); string& append(const string& str, size_t subpos, size_t sublen); string& append(const char* s); string& append(const char* s, size_t n); string& append(size_t n, char c); | string尾部插入字符或字符串(或子串) |
string& operator+=(const string& str); string& operator+=(const char* s); string& operator+=(char c); | string尾部插入单个字符或字符串 |
const char* c_str() const; | 返回char*类型指针指向的字符串 |
find / rfind string::find - C++ Reference string::rfind - C++ Reference | 返回string中第一个(最后一个)与参数指定内容(串或字符)相匹配的位置 |
find_first_of / find_last_of string::find_first_of - C++ Reference string::find_last_of - C++ Reference | 返回string中第一个(最后一个)与参数限定范围内的字符的位置 |
find_first_not_of / find_last_not_of string::find_first_not_of - C++ Reference string::find_last_not_of - C++ Reference | 返回string中第一个(最后一个)不在参数限定范围内的字符的位置 |
string substr(size_t pos = 0, size_t len = npos) const; | 在str中从pos位置开始,截取len个字符,然后将其返回 |
注意:
1. 在string尾部追加字符时,s.push_back(c) / s.append(1, c) / s += 'c'三种的实现方式差 不多,一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。
2. 对string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留好。
2.4 非成员函数
operator+ | 合并两个字符串(string或C语言格式)并返回合并后的string |
operator<< | 使string类型支持流输出 |
operator>> | 使string类型支持流提取 |
swap | 交换两个string对象的内容(直接交换size,capacity,str的值,效率高) |
getline | 从流中持续读取字符放入string对象中,直到遇到指定字符(默认为换行符) |