目录
一、为什么学习string类
1.1 C语言中的字符串
1.2 字符串在OJ面试中
二、标准库中的string类
2.1 string 介绍
2.2 编码格式
三、string 类常用接口
3.1 Member functions(成员函数)
3.1.1 构造函数(Construct)
3.1.2 赋值重载(operator=) 编辑
3.1.3 string类对象的容量操作(Capacity)
3.1.4 string类对象的访问(Element access)
3.1.5 string对象的访问及遍历操作(Iterators)
3.1.6 string类对象的修改(Modifiers)
3.1.7 string类对象的操作(String operations)
3.2 string类非成员函数(Non-member function overloads)
一、为什么学习string类
1.1 C语言中的字符串
C语言中,字符串是以 '\0' 结尾的一些字符的集合,为了操作方便,C标准库中提供了一些 str 系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想(面向对象思想),而且底层空间需要用户自己管理,稍不留神可能还会越界访问
1.2 字符串在OJ面试中
在OJ中,有关字符串的题目基本以string类的形式出现,而且在常规工作中,为了简单、方便、快捷,基本都使用string类,很少有人去使用C库中的字符串操作函数。
注:由于历史原因,string类并不归属到 STL 之中,但是 string类与 STL 很相像,就把 string类归属到 STL 中一起学习
学习 STL 一定要多翻阅 STL的官方文档查看详细解释 C++官网cppreference
但是官网的排布内容不是很好,推荐使用这个非官网的网站:cplusplus ,右上角切换到旧版体验更好
二、标准库中的string类
2.1 string 介绍
string类的文档介绍
- 1. 字符串是表示字符序列的类
- 2. 标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作单字节字符字符串的设计特性
- 3. string类是使用char(即作为它的字符类型,使用它的默认char_traits和分配器类型(关于模板的更多信息,请参阅basic_string)
- 4. string类是basic_string模板类的一个实例,它使用char来实例化basic_string模板类,并用char_traits和allocator作为basic_string的默认参数(根于更多的模板信息请参考basic_string)
- 5. 注意,这个类独立于所使用的编码来处理字节:如果用来处理多字节或变长字符(如UTF-8)的序列,这个类的所有成员(如长度或大小)以及它的迭代器,将仍然按照字节(而不是实际编码的字符)来操
总结:
- string是表示字符串的字符串类
- 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作
- string在底层实际是:basic_string 模板类的别名,typedef basic_string<char, char_traits, allocator>string
- 不能操作多字节或者变长字符的序列
在使用string类时,必须包含#include头文件 <string> 以及 using namespace std ,以及多翻阅参考cplusplus 的标准文档 string
- 这里为什么是 <string> 而没有 .h呢?
- 因为 C语言中已经有一个 <string.h>了,为了避免冲突和进行区别,所以使用 <string> 作为头文件
2.2 编码格式
string 是 basic_string 类模板使用字符类型 char 实例化得到的一个类
而且还以模板生成几个名字不同 string 类,这些类的主要区别在于编码方式的不同,链接
string 为什么要设计成模板呢?
因为编码格式的不同,一些字符存储所占用的空间不同
常见的一些编码格式:
(1)ASCII码,是美国设计的;ASCII码表是:计算机当中存的值,和字符的映射,但是只有256个字符的表示,用char表示
(2)Unicode,也叫做万国码。,Unicode是针对全世界的语言而设计的一种编码,常见的有utf-8 utf-16 utf-32
(3)gbk,gbk是叫做国标码,是针对中文创建的一个编码
编码方式对 basic_string 的影响如下
- char – 采用单字节编码;
- char16_t – 采用双字节编码
- char32_t – 采用四字节编码
这里我们以第一种进行学习,单字节编码格式的 string
平时使用的 string 本质上是 basic_string<char>, string 内部进行了 typedef
typedef basic_string<char, char_traits, allocator> string
-------------------我是分割线------------------
下面介绍string类常用的接口 ,要熟练掌握,其余的用时查阅即可
三、string 类常用接口
3.1 Member functions(成员函数)
3.1.1 构造函数(Construct)
提供了很多构造函数,只需要掌握其中最常用的几个就可以了,其余的如果有需要再查询文档
(constructor)函数名称 函数功能 string() (重点) 构造空的string类对象,即空字符 string(const char* s) (重点) 用字符数组来构造string类对象 string(const string&s) (重点) 拷贝构造函数 string(size_t n, char c) 用n个c字符来构造string类对象
测试代码
void Test_string()
{
string s1; // 构造空的string类对象s1
cout << "s1: " << s1 << endl;
string s2("hello world"); // 用C格式字符串构造string类对象s2
cout << "s2: " << s2 << endl;
string s3(s2); // 拷贝构造s3
cout << "s3: " << s3 << endl;
}
运行结果
3.1.2 赋值重载(operator=)
测试代码
void TestString()
{
string s1("hello");
string s2, s3, s4;
s2 = s1;
s3 = "world";
s4 = s2 + s3;
cout << "s2: " << s2 << endl;
cout << "s3: " << s3 << endl;
cout << "s4: " << s4 << endl;
}
运行结果至于析构函数(destructor)则简单了解即可,因为程序结束自动调用析构函数
3.1.3 string类对象的容量操作(Capacity)
掌握最常用的几个就可以了,其余的如果有需要再查询文档
函数名称 功能说明 size(重点) 返回字符串有效字符长度 length 返回字符串有效字符长度 capacity 返回空间总大小 empty(重点) 检测字符串释放为空串,是返回true,否则返回false clear(重点) 清空有效字符 reserve(重点) 为字符串预留空间** resize(重点) 将有效字符的个数该成n个,多出的空间用字符c填充
(1)size && length
size 和 length 的功能完全相同,这是早期 string 设计遗留的问题
测试代码
void TestString()
{
string s1("hello");
cout << "s1.size: " << s1.size() << endl;
cout << "s1.length: " << s1.length() << endl;
cout << "s1.capacity: " << s1.capacity() << endl;
string s2("aaaaa");
cout << "s2: " << s2 << endl;
cout << "s2.empty: " << s2.empty() << endl;
s2.clear();//清空有效字符串
cout << "s2.clear后: " << s2 << endl;
}
运行结果
(2)resize
resize 函数用来调整字符串大小,它一共分为三种情况:
- n 小于原字符串的 size,此时 resize 函数会将原字符串的 size 改为 n,但不会改变 capacity
- 大于原字符串的 size,但小于其 capacity,此时 resize 函数会将 size 后面的空间全部设置为字符 c 或默认的‘\0’
- 大于原字符串的 capacity,此时 resize 函数会将原字符串扩容,然后将size 后面的空间全部设置为字符 c 默认的‘\0’
测试代码
void TestString()
{
string s1("hello world!");
cout << "s1: " << s1 << endl;
cout << "s1.size: " << s1.size() << endl;
cout << "s1.capacity: " << s1.capacity() << endl;
s1.resize(20);
cout << "s1: " << s1 << endl;
cout << "s1.size: " << s1.size() << endl;
cout << "s1.capacity: " << s1.capacity() << endl;
s1.resize(15);
cout << "s1: " << s1 << endl;
cout << "s1.size: " << s1.size() << endl;
cout << "s1.capacity: " << s1.capacity() << endl;
s1.resize(5);
cout << "s1: " << s1 << endl;
cout << "s1.size: " << s1.size() << endl;
cout << "s1.capacity: " << s1.capacity() << endl;
}
运行结果
(3) reserve
reserve 用来扩容与预留空间,相当于C语言中的 realloc 函数,它分两种情况:
- n 大于原字符串的 capacity,此时 reserve 函数会将 capacity 扩容到 n
- n 小于等于原字符串的 capacity,capacity 容量不变 (不缩容)
注意区分 reserve 和 reverse
测试代码
void TestString()
{
string s1("hello world!");
cout << "s1: " << s1 << endl;
cout << "s1.size: " << s1.size() << endl;
cout << "s1.capacity: " << s1.capacity() << endl << endl;
s1.reserve(5);
s1.reserve(15);
cout << "s1: " << s1 << endl;
cout << "s1.size: " << s1.size() << endl;
cout << "s1.capacity: " << s1.capacity() << endl << endl;
s1.reserve(30);
cout << "s1: " << s1 << endl;
cout << "s1.size: " << s1.size() << endl;
cout << "s1.capacity: " << s1.capacity() << endl;
}
运行结果
3.1.4 string类对象的访问(Element access)
掌握 operator[] 使用即可,其它也是使用到了再查询文档
测试代码
void TestString()
{
string s1 = "hello world!";
for (size_t i = 0; i < s1.size(); ++i)
{
cout << s1[i] << endl;
}
}
运行结果
3.1.5 string对象的访问及遍历操作(Iterators)
Iterators 是 C++中的迭代器,可以把它当成指针来理解(string 和 vector),不是所有迭代器都是指针
也是老样子,掌握常用的几个即可,其它使用到再查询文档
函数名称 函数功能 begin() 返回一个指向字符串中第一个字符的迭代器 end() 返回一个指向字符串最后一个字符下一个位置(‘\0’)的迭代器 rbegin() 反向迭代器,返回一个指向字符串最后一个字符下一个位置(‘\0’)的迭代器 rend() 反向迭代器,返回一个指向字符串中第一个字符的迭代器
测试代码
void TestString()
{
string s1 = "12345";
string::iterator it = s1.begin();
while (it < s1.end())
{
(*it)++;
cout << *it;
++it;
}
}
运行结果
反向迭代器就是正向迭代器反过来使用,不再演示。实际上,范围 for 的底层就是使用迭代器实现的
3.1.6 string类对象的修改(Modifiers)
也是老样子,掌握常用的几个即可,其它使用到再查询文档
函数名称 功能说明 push_back 在字符串后尾插字符c append 在字符串后追加一个字符串 operator+=(重点) 在字符串后追加字符串str
(1) operator+=
operator+= 是运算符重载,用于向字符串尾插数据,支持尾插一个字符串以及尾插一个字符
测试代码
void TestString()
{
string s1 = "hello";
string s2 = "world";
s1 += s2;
cout << s1 << endl;
}
运行结果
(2)push_back 、append
push_back 是在字符串后尾插字符c,append 是在字符串后追加一个字符串,这些都与 += 类似,设计有些多余,不演示了
(3)insert 和 erase
insert 函数用于向在字符串的 pos 处插入数据,erase 用来从 pos 位置开始向后删除 len 个字符,因为时间复杂度的问题,很少使用,有需要直接看文档,不演示了
3.1.7 string类对象的操作(String operations)
老规矩,掌握常用的几个即可,其它使用到再查询文档
函数名称 功能说明 c_str(重点) 返回C格式字符串 find(重点) 从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置 rfind 从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置 substr 在str中从pos位置开始,截取n个字符,然后将其返回
(1)c_str
在某些场景中只支持对C形式的字符串,即字符数组进行操作,比如网络传输、fopen,而不支持对C++中的 string 对象进行操作,所以 string 提供了 c_str,用于返回C形式的字符串,即以 ‘\0’ 结尾的字符串
测试代码
void TestString()
{
string s1 = "hello world";
const char* str = s1.c_str();
cout << str << endl;
}
运行结果
(2)find
find 用于返回 一个字符或一个字符数组或一个string对象 在 string 中首次出现的位置,如果找不到就返回 npos:
说明一下 npos,npos 是一个无符号数,npos = -1 即代表无符号的最大取值
测试代码
void TestString()
{
string s1 = "hello world";
cout << s1.find('o') << endl;
cout << s1.find("or") << endl;
cout << s1.find("a") << endl;
}
运行结果
(3)rfind
rfind 是从末尾开始找指定内容,与 find 查找方向相反,不演示了
(4)substr
substr 返回一个新构造的字符串对象,从字符位置 pos 开始,跨越 len 个字符或直到字符串结尾
测试代码
void TestString()
{
string s1 = "hello world!!";
cout << s1.substr(0, 5) << endl;
cout << s1.substr(6, 6) << endl;
}
运行结果
3.2 string类非成员函数(Non-member function overloads)
掌握常用的几个即可,其它使用到再查询文档
函数 功能说明 operator+ 尽量少用,因为传值返回,导致深拷贝效率低 operator>>(重点) 输入运算符重载 operator<<(重点) 输出运算符重载 getline(重点) 获取一行字符串 relational operators(重点) 大小比较
(1) relational operators
两个 string 对象之间的大小关系函数重载,直接使用就好了,不演示了
(2) operator>> 和 operator<<
流插入与流提取运算符重载,这两个重载的作用就是为了让 string 对象支持直接输出和输入
(3)getline
C语言中的 scanf 函数和 C++ 中的 cin 都是以空格、换行等作为不同数据之间的分割标志的,即当它们遇到这些符号时就会停止读。C语言提供了 gets 函数来读取一行字符,C++ 则是提供了 getline 函数来读取一行字符,并且我们还可以自己指定结束标志符,不演示了
----------------我是分割线---------------
文章到这里就结束了,下一篇即将更新