
前言
在C语言中, 我们会遇到很多与字符串有关的地方, 不管是项目中还是oj的算法练习题中,
为了方便C标准库中提供了一些str系列的库函数, 但是这些库函数和字符串是分开的, 不太符合OOP的思想, 而且底层空间需要用户自己管理, 稍不留神就会有越界的风险.
所以在常规工作中, 为了简单, 方便, 快捷, 基本都会使用string类, 很少有人去使用C标准库中的字符串操作函数.
下面我们就来介绍string类
string类的文档介绍
需要注意的是在使用string类时, 必须包含头文件#include<string>和using namespace std;
string常用的接口说明
string初始化
construct(构造函数)

我们会发现构造函数提供了很多接口, 由于历史发展原因很多接口设计的很冗余, 我们只需要学习一些掌握几个常用的重点接口就行, 其他接口做一个了解, 遇到使用的问题再去文档查就行.

cpp
void TestConstructor()
{
string s1;
string s2("hello world");
string s3(s2);
}
operator=


cpp
void Testoperator()
{
string s1 = "x";
string s2 = "hello world!";
string s3 = s2;
}
string类对象的容量操作
size
cpp
size_t size() const;
返回字符串有效字符长度

cpp
void Testcapacity()
{
string s1 = "hello world";
cout << s1.size() << endl;
}
length
cpp
size_t length() const;
它也是返回字符串的长度不是它返回的是以字节为单位
该数值为构成字符串内容的实际字节数,不一定等同于字符串的存储容量。
string::size 与 string::length 作用完全相同,二者会返回一模一样的数值
resize
cpp
void resize (size_t n);
void resize (size_t n, char c);
调整字符串长度
将字符串调整为 n 个字符的长度。
若 n 小于字符串当前长度,截取前 n 个字符,舍弃后续字符。
若 n 大于字符串当前长度,则在末尾补足字符,使总长度达到 n。若指定字符 c,新增字符均填充为 c;未指定则默认填充空字符。
capacity
cpp
size_t capacity() const;
返回已分配存储空间的大小
返回当前为字符串分配的存储空间大小,以字节为单位。

该容量不一定等同于字符串长度,二者可以相等,也可以前者更大。多出的空间能够让字符串新增字符时,优化自身运行操作。
reserve
cpp
void reserve (size_t n = 0);
申请调整容量
要求将字符串容量适配规划的尺寸变更,最大可调整至 n 个字符长度。
- 若数值 n 大于字符串当前容量,该函数会将容器容量扩充至 n 个字符及以上。
- 其余情况下,该操作仅为缩减字符串容量的非强制性请求,容器可自行优化处理,最终容量也可保留为大于 n 的数值。
此函数不会改变字符串长度,也无法修改字符串内容 。

clear
cpp
void clear();
清空字符串
清除字符串内的内容,使其变为空字符串(字符长度为 0)。

可见并没有清除s1的申请的空间.
empty
cpp
bool empty() const;
检测字符串是否为空
判断该字符串是否为空(即长度是否为 0)。
此函数不会以任何形式修改字符串数值。
string类对象的访问及遍历操作
operator[]
cpp
char& operator[] (size_t pos);
const char& operator[] (size_t pos) const;
获取字符串字符
返回字符串中指定位置的字符引用

因为返回值为引用, 所以可以遍历也可以修改.
back+front
cpp
char& back();const char& back() const;
char& front();const char& front() const;
back
获取最后一个字符
返回字符串最后一个字符的引用。
不可对空字符串调用该函数。
front
获取首个字符
返回字符串首个字符的引用。
不可对空字符串调用该函数。
begin+end迭代器
cpp
iterator begin();const_iterator begin() const;
返回指向起始位置的迭代器
返回一个指向字符串首个字符的迭代器。
若字符串对象带有常量限定符,该函数返回常量迭代器;否则返回普通迭代器。
cpp
iterator end();const_iterator end() const;
返回末尾迭代器
返回一个指向字符串末尾下一位置字符的迭代器。
-
末尾下一位置字符是逻辑上紧随字符串最后一个字符之后的虚拟字符,该字符不可解引用。
-
标准库函数所用的区间范围不包含尾迭代器指向的元素,因此该函数常与字符串起始迭代器配合使用,划定包含字符串全部字符的区间。
-
若字符串为空对象,该函数的返回结果与字符串起始迭代器一致。

这里简单介绍一下什么的迭代器
在 C++ 的 std::string 里,迭代器 是一种像指针一样的对象,用来逐个访问或修改字符串中的每个字符。你可以把它理解为"遍历字符串的通用方式"。
rbegin+rend迭代器
cpp
reverse_iterator rbegin();const_reverse_iterator rbegin() const;
返回指向反向起始位置的反向迭代器
-
返回一个指向字符串最后一个字符的反向迭代器,也就是字符串的反向起始位置。
-
反向迭代器以倒序方式遍历:迭代器递增时,会向字符串起始位置移动。
-
反向起始迭代器指向的字符,紧邻常规末尾迭代器所指向字符的前一位。
cpp
reverse_iterator rend();const_reverse_iterator rend() const;
返回指向逆向末尾的逆向迭代器
-
返回一个逆向迭代器,该迭代器指向字符串首个字符的前一位虚拟元素,此位置视作字符串的逆向末尾。
-
字符串逆向起始迭代器与逆向末尾迭代器之间的区间,包含字符串所有字符,且字符呈倒序排列。
-

auto 和 范围for
从上面的 std::string 迭代器 ,你会发现用传统写法声明迭代器类型有点啰嗦。auto 和范围 for 循环正是 C++11 引入的"简化神器",让遍历字符串变得格外清爽。
auto自动推导类型
auto 的作用是让编译器帮你自动推导变量的类型。它必须立即初始化,编译器根据初始化表达式猜出类型。
cpp
string str = "hello";
// 传统写法:类型名又长又麻烦
string::iterator it = str.begin();
string::const_iterator cit = str.cbegin();
string::reverse_iterator rit = str.rbegin();
// 使用 auto 之后
auto it = str.begin(); // 自动推导为 string::iterator
auto cit = str.cbegin(); // 自动推导为 string::const_iterator
auto rit = str.rbegin(); // 自动推导为 string::reverse_iterator
这样一来上面是for循环就变成

范围for
范围 for 循环提供了一种不用显式写迭代器就能遍历容器所有元素的语法。
cpp
for (元素声明 : 容器) {
// 使用当前元素
}
范围for在string类中的使用
cpp
std::string str = "hello";
// 1. 只读遍历(拷贝字符,修改不影响原字符串)
for (char c : str) {
std::cout << c; // 输出 hello
}
// 2. 使用 auto 进一步简化
for (auto c : str) {
std::cout << c; // c 被推导为 char
}
// 3. 想要修改原字符串中的字符:必须用引用
for (auto& c : str) {
c = toupper(c); // 将 str 变为 "HELLO"
}
// 4. 只读但避免拷贝(最常用):常量引用
for (const auto& c : str) {
std::cout << c; // 高效只读
}

注意事项
-
范围 for 不能用于改变容器结构
在循环内往字符串中插入或删除字符会导致迭代器失效,这是未定义行为。如果确实需要增删,就得退回到普通迭代器循环并小心处理
it的更新。 -
auto 和范围 for 一起用时,想清楚是要拷贝还是引用
for (auto c : s)会拷贝每个字符,修改c不影响原字符串;for (auto& c : s)才是引用原始字符,能够修改。 -
反向遍历
范围 for 只能正向从头到尾,如果需要反向遍历,还是要用迭代器:
for (auto it = str.rbegin(); it != str.rend(); ++it)。
string类对象的修改操作
operator+=
cpp
string& operator+= (const string& str);
string& operator+= (const char* s);
string& operator+= (char c);
追加至字符串
- 通过在字符串现有内容末尾增添字符来扩充字符串长度:

append
cpp
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);
追加至字符串
- 通过在字符串现有内容末尾增添字符来扩展字符串
cpp
void TestModifier()
{
string s;
string s1 = "hello";
string s2 = "world 2026";
s.append(s1); //"hello"
s.append(s2,6,4); //"2026"
s.append("hello world"); //"hello world"
s.append("hello world", 5); //"hello"
}
push_back
cpp
void push_back (char c);
向字符串追加字符
- 将字符c添加至字符串末尾,字符串长度增加一位。

insert
cpp
string& insert (size_t pos, const string& str);
string& insert (size_t pos, const string& str, size_t subpos, size_t sublen);
string& insert (size_t pos, const char* s);
string& insert (size_t pos, const char* s, size_t n);
插入字符串
- 在位置参数指定的字符前方插入额外字符至字符串中
cpp
void TestModifier()
{
std::string str = "to be question";
std::string str2 = "the ";
std::string str3 = "or not to be";
std::string::iterator it;
// used in the same order as described above:
str.insert(6, str2); // to be (the )question
str.insert(6, str3, 3, 4); // to be (not )the question
str.insert(10, "that is cool", 8); // to be not (that is )the question
str.insert(10, "to be "); // to be not (to be )that is the question
}
erase
cpp
string& erase (size_t pos = 0, size_t len = npos);
iterator erase (iterator p);
iterator erase (iterator first, iterator last);
从字符串中删除字符
删除字符串的部分内容,缩短字符串长度:
-
按序列删除
删除从位置pos开始、长度为len的字符片段;若字符串长度不足或len取值为string::npos,则删除至字符串末尾。
默认参数会清空字符串内所有字符,效果等同于清空成员函数。 -
按单个字符删除
删除指针p指向的字符。 -
按区间删除
删除左闭右开区间[首迭代器,尾迭代器 )范围内的字符序列 。
cpp
void TestModifier()
{
string s1 = "hello world";
string s2 = "hello zhengqing";
string s3 = "hello ruanjian";
s1.erase(); //""空
auto it = s2.begin();
s2.erase(it); //"ello zhengqing"删除了首字符
auto left = s3.begin();
auto right = s3.end();
right -= 8;
s3.erase(left, right); //"ruanjian"删除[0,6)
}
swap
cpp
void swap (string& str);
交换字符串数值
- 将当前字符串容器的内容与另一个字符串对象的内容互换,二者长度可以不同。
- 调用该成员函数后,当前对象会拥有调用前另一字符串对象的内容,另一字符串对象则会拥有调用前当前对象的内容。
- 注意存在同名的非成员交换函数,该函数对此算法进行了优化重载,运行效果与本成员函数一致。
cpp
void TestModifier()
{
string s1 = "how are you";
string s2 = "what is it";
s1.swap(s2);//s1:"what is it"
//s2:"how are you"
}
pop_back
cpp
void pop_back();
删除最后一个字符
- 移除字符串的最后一个字符,字符串长度随之减少一位。
string的运算操作
c_str
cpp
const char* c_str() const;
获取对应的 C 语言字符串
-
返回一个指向字符数组的指针,该数组包含以空字符结尾的字符序列,也就是 C 语言字符串,用于表示字符串对象的当前值。
-
该数组包含构成字符串对象值的全部字符序列,并在末尾额外增添一个终止空字符('\0')。

data
cpp
const char* data() const;
返回一个指向字符数组的指针,该数组包含与字符串对象取值完全一致的字符序列。
访问 data ()+size () 位置的值会引发未定义行为:无法保证此函数返回的指针所指向的字符序列以空字符结尾。如需具备该保障的函数,可参考 string::c_str。
程序不得修改该序列内的任意字符。
copy
cpp
size_t copy (char* s, size_t len, size_t pos = 0) const;
从字符串中复制字符序列
-
将字符串对象当前值的子字符串复制到s指向的数组中,该子字符串包含从位置pos开始的len个字符。
-
该函数不会在复制内容的末尾追加空字符。
find
cpp
size_t find (const string& str, size_t pos = 0) const;
size_t find (const char* s, size_t pos = 0) const;
size_t find (const char* s, size_t pos, size_t n) const;
size_t find (char c, size_t pos = 0) const;
在字符串中查找内容
-
根据参数指定的字符序列,在字符串中检索其首次出现的位置。
-
若指定起始位置,检索仅包含该位置及之后的字符,忽略该位置之前所有可能匹配的内容。
-
需注意,该方法与字符匹配查找函数不同。当检索多个字符组成的序列时,并非单个字符匹配即可,必须完整匹配整个字符序列。
-
首次匹配到的首个字符位置。
-
若未找到匹配项,该函数会返回 string::npos。
-
size_t 属于无符号整数类型,与成员类型 string::size_type 一致
cpp
string s1 = "hello world how are you hello bye.";
string s2 = "hello";
size_t found = s1.find(s2);
if (found != string::npos)
{
cout << "first 'hello' fount at" << endl;
}
found = s1.find("hello world", found + 1, 5);
if (found != string::npos)
{
cout << "second 'hello' found at" << endl;
}
found = s1.find("how");
if (found != string::npos)
{
cout << "'how' also found at" << endl;
}
found = s1.find('.');
if (found != string::npos)
{
cout << "'.'found at" << endl;
}
rfind
cpp
size_t rfind (const string& str, size_t pos = npos) const;
c-string (2)|size_t rfind (const char* s, size_t pos = npos) const;
buffer (3)|size_t rfind (const char* s, size_t pos, size_t n) const;
character (4)|size_t rfind (char c, size_t pos = npos) const;
查找字符串中内容的最后一次出现位置
-
在字符串中检索参数指定字符序列的最后一处匹配位置。
-
若设定位置参数,检索范围仅包含起始位置不超过该数值的字符序列,忽略此后出现的所有匹配内容。
substr
cpp
string substr (size_t pos = 0, size_t len = npos) const;
生成子字符串
- 返回一个新创建的字符串对象,其初始值为该对象某一子字符串的副本。
- 该子字符串从字符位置 pos 开始,截取长度为 len 的字符内容,若剩余字符不足指定长度,则截取至字符串末尾。
string类的非成员函数
relational operators
cpp
|(1)|bool operator== (const string& lhs, const string& rhs);bool operator== (const char* lhs, const string& rhs);bool operator== (const string& lhs, const char* rhs);
|(2)|bool operator!= (const string& lhs, const string& rhs);bool operator!= (const char* lhs, const string& rhs);bool operator!= (const string& lhs, const char* rhs);
|(3)|bool operator< (const string& lhs, const string& rhs);bool operator< (const char* lhs, const string& rhs);bool operator< (const string& lhs, const char* rhs);
|(4)|bool operator<= (const string& lhs, const string& rhs);bool operator<= (const char* lhs, const string& rhs);bool operator<= (const string& lhs, const char* rhs);
|(5)|bool operator> (const string& lhs, const string& rhs);bool operator> (const char* lhs, const string& rhs);bool operator> (const string& lhs, const char* rhs);
|(6)|bool operator>= (const string& lhs, const string& rhs);bool operator>= (const char* lhs, const string& rhs);bool operator>= (const string& lhs, const char* rhs);
字符串关系运算符
对左侧和右侧的字符串对象执行对应的比较运算。
这些函数通过字符串比较函数完成比对操作。
该类运算符在< string >头文件中重载定义。
cpp
#include <iostream>
#include <vector>
int main ()
{
std::string foo = "alpha";
std::string bar = "beta";
if (foo==bar) std::cout << "foo and bar are equal\n";
if (foo!=bar) std::cout << "foo and bar are not equal\n";
if (foo< bar) std::cout << "foo is less than bar\n";
if (foo> bar) std::cout << "foo is greater than bar\n";
if (foo<=bar) std::cout << "foo is less than or equal to bar\n";
if (foo>=bar) std::cout << "foo is greater than or equal to bar\n";
return 0;
}
| Output: |
|---|
| foo and bar are not equal foo is less than bar foo is less than or equal to bar |
swap-free/
cpp
void swap (string& x, string& y);
交换两个字符串的值
交换字符串对象x与y的值,调用该函数后,x会赋值为调用前y的数值,y则赋值为调用前x的数值。
这是通用交换算法的重载版本,该算法通过两个对象互相移交内部数据所有权来提升运行效率,也就是两个字符串仅互换数据引用,并不会实际拷贝字符,效果等同于调用x.swap(y)。
operator>>+operator<<
cpp
istream& operator>> (istream& is, string& str);
ostream& operator<< (ostream& os, const string& str);
从流中提取字符串
-
从输入流中提取字符串,并将字符序列存入字符串变量,变量原有内容会被覆盖替换。
-
该函数对右移提取运算符进行重载,功能与输入流针对 C 风格字符串的提取运算符一致,只不过作用对象为字符串类对象。
-
每一个提取到的字符,都会如同调用字符串尾部添加成员函数一般,追加到字符串末尾.
-
需注意,输入流提取操作会将空白字符视作分隔符;因此该操作仅能从数据流中提取单个字词。若想要提取整行文本,可查阅全局函数 getline 针对字符串的重载用法。
将字符串插入输出流
-
把字符串对应的字符序列插入输出流对象中。
-
该函数重载左移运算符,其运行逻辑与输出流针对 C 风格字符串的左移运算符一致,适用于字符串对象。
getline
cpp
istream& getline (istream& is, string& str, char delim);
istream& getline (istream& is, string& str);
从流中读取一行存入字符串
- 从输入流中提取字符并存储到字符串内,直至读取到分隔符为止;第二种用法中则以换行符作为分隔判定依据。
- 若读取过程中抵达文件末尾,或是输入操作出现其他异常,字符提取动作也会随即终止。
- 一旦检索到分隔符,该符号会被读取并舍弃,不会存入字符串,后续输入操作将从分隔符的下一位字符开始执行。
- 请注意,调用该操作前字符串内原有内容,都会被新读取的字符序列覆盖替换。
- 每一个读取到的字符,都会以调用字符串尾部追加成员函数的形式依次存入字符串。

结语
由于C++的设计较早, 历史发展周期长, 导致string的很多接口设计冗余, 我就挑选了比较重要的讲了一下, 感兴趣的朋友可以去官方文档详细查看, 谢谢大家观看, 欢迎大家多多评论交流.


