
C++专栏:C++_Yupureki的博客-CSDN博客
目录
[1. 为什么学习string类?](#1. 为什么学习string类?)
[1.1 C语言字符串的局限性](#1.1 C语言字符串的局限性)
[1.2 字符串的重要性](#1.2 字符串的重要性)
[2. 标准库中的string类](#2. 标准库中的string类)
[2.1 string类基础](#2.1 string类基础)
[2.2 C++11新特性:auto和范围for](#2.2 C++11新特性:auto和范围for)
[3. string基本操作](#3. string基本操作)
[4 string访问和遍历](#4 string访问和遍历)
[5. string的修改操作](#5. string的修改操作)
[6. string类的模拟实现](#6. string类的模拟实现)
[6.1 浅拷贝问题](#6.1 浅拷贝问题)
[6.2 深拷贝解决方案](#6.2 深拷贝解决方案)
前言
在C++编程中,字符串处理是我们日常开发中最常见的任务之一。C语言中,我们使用字符数组和\0
结尾的方式来处理字符串,但这种方式存在诸多不便:需要手动管理内存、容易发生越界访问、功能有限且不符合面向对象的思想。
C++标准库中的string
类彻底改变了这一局面,它封装了字符串的存储和操作,提供了丰富而安全的接口,让我们能够更加高效、安全地处理字符串。无论是算法竞赛、日常开发还是面试求职,string
类都是我们必须掌握的重要工具。
本文将全面介绍C++ string
类的使用方法和实现原理,帮助大家深入理解并熟练运用这个强大的工具。

1. 为什么学习string类?
1.1 C语言字符串的局限性
在C语言中,字符串是以\0
结尾的字符数组,虽然标准库提供了一系列字符串操作函数,但存在明显问题:
cpp
char str[20] = "hello";
strcat(str, " world"); // 需要确保数组足够大,否则可能越界
并且在C语言中,字符串的处理相关的函数极少。如果现在我要求你对"hello world"进行以下操作:在'e'前面插入5个'x',删除第一个'l',找到字符串中第一个'o',删除所有的' ',最后将字符串再改回"hello world"。你看到这,似乎并不是很难,但是特别麻烦。每一个要求都需要十几行的代码,如果加在一起便十分复杂。
那么string就解决了这个问题,因为集成了我们所需的几乎所有处理字符串的操作函数
1.2 字符串的重要性
https://leetcode-cn.com/problems/add-strings/
在OJ中,有关字符串的题目基本以string类的形式出现,并且在竞赛中,对于字符串的处理也十分频繁,如果在C中死板的一行行写,那么就十分低效
2. 标准库中的string类
2.1 string类基础
string为C++中十分重要的一个板块,为此我们专门在专业的C++相关文档中查阅并讲解
http://www.cplusplus.com/reference/string/string/?kw=string
同时在使用string类时,必须包含#include头文件以及using namespace std;
2.2 C++11新特性:auto和范围for
auto关键字
auto让编译器自动推导变量类型,使代码更简洁
cpp
int main()
{
int a = 10;
auto b = a;
auto c = 'a';//auto根据赋值的类型,自动推导变量的类型,因此auto的变量必须初始化
auto d = func1()
}
范围for循环
使用auto简化容器遍历:
cpp
string str = "hello";
// 传统遍历
for (size_t i = 0; i < str.size(); ++i) {
cout << str[i];
}
// 范围for遍历
for (auto ch : str) {
cout << ch; // 自动遍历每个字符
}
// 如果需要修改字符串,使用引用
for (auto& ch : str) {
ch = toupper(ch); // 将字符转为大写
}
3. string基本操作
构造字符串
string是个类,因此具有构造函数
cpp
string s1; // 空字符串
string s2("hello"); // 用C字符串构造
string s3(s2); // 拷贝构造
string s4(5, 'A'); // "AAAAA"
string s5 = "world"; // 赋值构造

容量操作
函数名称
size(重点) 返回字符串有效字符长度
length 返回字符串有效字符长度
capacity 返回空间总大小
empty (重点) 检测字符串释放为空串,是返回true,否则返回false
clear (重点) 清空有效字符
reserve (重点)为字符串预留空间**
resize (重点) 将有效字符的个数该成n个,多出的空间用字符c填充
cpp
string str = "hello";
cout << str.size(); // 5,返回有效字符长度
cout << str.length(); // 5,与size()相同
cout << str.capacity(); // 返回总容量
cout << str.empty(); // 是否为空
str.clear(); // 清空字符串
str.resize(10, 'x'); // 调整大小,多出部分用'x'填充
str.reserve(100); // 预留空间,提高效率
4 string访问和遍历
访问
string重载了operator[],使其能够像操作数组一样利用[]来访问元素
cpp
int main ()
{
std::string str ("Test string");
for (int i=0; i<str.length(); ++i)
{
std::cout << str[i];//利用[]和下标来访问元素
}
return 0;
}
遍历
begin和end
begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器
cpp
string str = "hello";
// 迭代器
for (auto it = str.begin(); it != str.end(); ++it) {
cout << *it;//从左到右访问->hello
}
rbegin和rend
rbegin获取一个字符的反向迭代器 + rend获取第一个字符的位置
cpp
string str("hello")
for (auto it = str.rbegin(); it != str.rend(); ++it) {
cout << *it;//从右往左访问->olleh
}
cpp
str.push_back('!'); // 尾部添加字符
5. string的修改操作
函数名称 功能说明
push_back 在字符串后尾插字符c
cpp
str.push_back('!'); // 尾部添加字符
append 在字符串后追加一个字符串
cpp
str.append(" world"); // 追加字符串
operator+= (重点) 在字符串后追加字符串str
cpp
str += "!!!"; // 最常用的追加方式
c_str(重点) 返回C格式字符串
find(重点) 从字符串pos位置开始往后找字符c/字符串,返回该字符在字符串中的位置
cpp
size_t pos = str.find("world"); // 查找子串
rfind (重点) 从字符串pos位置开始往前找字符c/字符串,返回该字符在字符串中的位置
substr 在str中从pos位置开始,截取n个字符,然后将其返
cpp
if (pos != string::npos) {
string sub = str.substr(pos, 5); // 截取子串
}
erase 删除子串
cpp
str.erase(5, 4);// 删除子串(从起始地点为5的位置开始删除4个字符)
6. string类的模拟实现
6.1 浅拷贝问题
浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致 多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉
cpp
class String {
private:
char* _str;
public:
String(const char* str = "") {
_str = new char[strlen(str) + 1];
strcpy(_str, str);
}
// 问题:默认拷贝构造是浅拷贝!
~String() { delete[] _str; }
};
void Test() {
String s1("hello");
String s2(s1); // 浅拷贝!s1和s2指向同一内存
} // 析构时同一内存被释放两次,程序崩溃
6.2 深拷贝解决方案
如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给 出。一般情况都是按照深拷贝方式提供。
cpp
class String {
public:
String(const char* str = "") {
_str = new char[strlen(str) + 1];
strcpy(_str, str);
}
// 深拷贝构造
String(const String& s) {
_str = new char[strlen(s._str) + 1];
strcpy(_str, s._str);
}
// 深拷贝赋值
String& operator=(const String& s) {
if (this != &s) {
char* temp = new char[strlen(s._str) + 1];
strcpy(temp, s._str);
delete[] _str;
_str = temp;
}
return *this;
}
~String() { delete[] _str; }
private:
char* _str;
};
现代写法(推荐)
cpp
class String {
public:
String(const char* str = "") {
_str = new char[strlen(str) + 1];
strcpy(_str, str);
}
// 拷贝构造:利用临时对象和swap
String(const String& s) : _str(nullptr) {
String temp(s._str);
swap(_str, temp._str);
}
// 赋值:参数为值传递,利用swap
String& operator=(String s) {
swap(_str, s._str);
return *this;
}
~String() { delete[] _str; }
private:
char* _str;
};
结语
string
类是C++中极其重要的组件,它让我们能够更加安全、高效地处理字符串。通过本文的学习,希望大家能够:
-
熟练掌握
string
类的各种常用接口 -
理解深拷贝和浅拷贝的区别及重要性
-
能够自己实现一个简单的
string
类 -
在实战中灵活运用
string
解决各种字符串问题
练习建议:
-
实现自己的String类(包含基本操作)
-
完成leetcode上的字符串相关题目
-
阅读标准库中string的源码实现