C++ string类接口手册:从新手到开发者的进阶之路
C++ string类接口手册:从新手到开发者的进阶之路
C++中的string类是处理字符串的重要工具,它提供了丰富的构造函数和操作方法,使得字符串处理变得更加简单和安全。本文将详细介绍string类的构造、常用操作以及遍历方式,帮助读者从新手进阶到开发者。
C++风格字符串
C++ 提供了 std::string
(后面简写为 string
)类用于字符串的处理。string
类定义在 C++ 头文件 <string>
中,注意和头文件 <cstring>
区分,<cstring>
其实是对 C 标准库中的 <string.h>
的封装,其定义的是一些对 C 风格字符串的处理函数。
尽管 C++ 支持 C 风格字符串,但在 C++ 程序中最好还是不要使用它们。这是因为 C 风格字符串不仅使用起来不太方便,而且极易引发程序漏洞,是诸多安全问题的根本原因。与 C 风格字符串相比,string
不必担心内存是否足够、字符串长度,结尾的空白符等等。string
作为一个类出现,其集成的成员操作函数功能强大,几乎能满足所有的需求。从另一个角度上说,完全可以把 string
当成是 C++ 的内置数据类型,放在和 int
、double
等内置类型同等位置上。
std::string
标准库提供的一个自定义类类型 basic_string
,string
类本质上其实是 basic_string
类模板关于 char
型的实例化。使用起来不需要关心内存,直接使用即可。
string的构造
basic_string
的常用构造——查看 C++ 参考文档(cppreference-zh-20211231.chm)
basic_string(); // 无参构造
basic_string(size_type count, CharT ch, const Allocator& alloc = Allocator()); // count + 字符
basic_string(const basic_string& other, size_type pos, size_type count, const Allocator& alloc = Allocator()); // 接收一个 basic_string 对象
basic_string(const CharT* s, size_type count, const Allocator& alloc = Allocator()); // 接收一个 C 风格字符串
basic_string
是一个模板类,它是 std::string
的基类。这里涉及到后面继承与模板的知识,现在我们掌握使用方法即可。
在创建字符串对象时,我们可以直接使用 std::string
作为类名,如 std::string str = "hello"
。这是因为 C++ 标准库已经为我们定义了 std::string
这个类型的别名。
string对象常用的构造
string(); // 默认构造函数,生成一个空字符串
string(const char* rhs); // 通过 C 风格字符串构造一个 string 对象
string(const char* rhs, size_type count); // 通过 rhs 的前 count 个字符构造一个 string 对象
string(const string& rhs); // 拷贝构造函数
string(size_type count, char ch); // 生成一个 string 对象,该对象包含 count 个 ch 字符
string(InputIt first, InputIt last); // 以区间 [first, last) 内的字符创建一个 string 对象
还可以用拼接的方式构造 string
原理:basic_string
对加法运算符进行了默认重载(后续会学到),其本质是通过 + 号进行计算后得到一个 basic_string
对象,再用这个对象去创建新的 basic_string
对象
// 采取拼接的方式创建字符串
// 可以拼接 string、字符、C 风格字符串
string str3 = str1 + str2;
string str4 = str2 + ',' + str3;
string str5 = str2 + ",world!";
#include <string.h>
#include <iostream>
#include <string>
using namespace std;
using std::string;
int main()
{
string str;
cout << "str:" << str << endl;
cout << "is str empty:" << str.empty() << endl;
cout << "str'size :" << str.size() << endl;
// string(size_type count ,char ch) 生成一个string字符串
// 对象,该对象包含count个ch字符
// 创建一个str1有5个a字符
string str1(5, 'a');
// 错误要转化为C风格字符串
// cout << strlen(str);
cout << strlen(str1.c_str()) << endl;
cout << "str1:" << str1 << endl;
cout << "is str1 empty:" << str1.empty() << endl;
cout << "str1'size :" << str1.size() << endl;
// 通过c风格字符串创建字符串
const char* a = "hello";
string str2(a);
cout << "str2:" << str2 << endl;
// string(const char * rhs, size_type count);
// 通过rhs的前count个字符构造一个string对象
string str3("ssssss", 2);
string str4(a, 3);
cout << "str3:" << str3 << endl;
cout << "str4:" << str4 << endl;
// 使用拷贝构造函数创建字符串
string str5(str2);
string str6 = str3;
cout << "str5:" << str5 << endl;
cout << "str6:" << str6 << endl;
// 已区间内的字符创建字符串
auto it2 = str1.begin();
auto it3 = str1.end();
string str7(it2, it3);
cout << "str7:" << str7 << endl;
// 使用字符串拼接来创建字符串
string str8 = str2 + str3;
string str9 = str2 + ",wwww";
cout << "str8:" << str8 << endl;
cout << "str9:" << str9 << endl;
return 0;
}
string的常用操作
// C++ 字符串转为 C 字符串(两个)
const CharT* data() const;
const CHarT* c_str() const;
bool empty() const; // 判空
size_type size() const; // 获取字符数
size_type length() const;
void push_back(CharT ch); // 字符串结尾追加字符
// 在字符串的末尾添加内容,返回修改后的字符串
basic_string& append(size_type count, CharT ch); // 添加 count 个字符
basic_string& append(const basic_string& str); // 添加字符串
basic_string& append(const basic_string& str, // 从原字符串的 pos 位置,添加字符串的 count 个字符
size_type pos, size_type count);
basic_string& append(const charT* s); // 添加 C 风格字符串
// 查找子串
size_type find(const basic_string& str, size_type pos = 0) const; // 从 C++ 字符串的 pos 位开始查找 C++ 字符串
size_type find(CharT ch, size_type pos = 0) const; // 从 C++ 字符串的 pos 位开始查找字符 ch
size_type find(const CharT* s, size_type pos, size_type count) const; // 从 C++ 字符串的 pos 位开始,去查找 C 字符串的前 count 个字符
实践一下 string 的各种操作,体会 C++ 字符串的遍历。
补充:两个 basic_string
字符串比较,可以直接使用 ==
等符号进行判断
原理:basic_string
对 ==
运算符进行了默认重载(后续会学到)
// 非成员函数
bool operator==(const string& lhs, const string& rhs);
bool operator!=(const string& lhs, const string& rhs);
bool operator>(const string& lhs, const string& rhs);
bool operator<(const string& lhs, const string& rhs);
bool operator>=(const string& lhs, const string& rhs);
bool operator<=(const string& lhs, const string& rhs);
#include <string.h>
#include <iostream>
#include <string>
using namespace std;
using std::string;
int main()
{
string str("hello");
cout << "str:" << str << endl;
cout << "is str empty:" << str.empty() << endl;
cout << "str'size :" << str.size() << endl;
cout << "str'length:" << str.length() << endl;
str.push_back('!');
cout << "str:" << str << endl;
size_t pos = str.find('e');
cout << pos << endl;
string str2("lly");
cout << str.find(str2) << endl;
return 0;
}
string的遍历(重点)
string
实际上也可以看作是一种存储 char
型数据的容器,对 string
的遍历方法是之后对各种容器遍历的一个铺垫。
通过下标遍历
string
对象可以使用下标操作符 []
进行访问。
// 使用下标遍历
for (size_t idx = 0; idx < str.size(); ++idx)
{
cout << str[idx] << " ";
}
cout << endl;
需要注意的是操作符 []
并不检查索引是否有效,如果索引超出范围,会引起未定义的行为。而函数 at()
会检查,如果使用 at()
的时候索引无效,会抛出 out_of_range
异常
string str("hello");
cout << str.at(4) << endl; // 输出 o
cout << str.at(5) << endl; // 运行时抛出异常
增强for循环遍历
针对容器,可以使用增强 for 循环进行遍历其中的元素。增强 for 循环经常和 auto
关键字一起使用,auto
关键字可以自动推导类型。
for (auto& ch : str) // 只要是 str 中的元素,就一一遍历
{
cout << ch << " ";
}
cout << endl;
迭代器方式进行遍历
string
字符串利用连续空间存储字符,所以可以利用地址遍历。这里我们提出一个概念——迭代器。迭代器可以理解为是广义的指针。它可以像指针一样进行解引用、移位等操作。迭代器是容器用来访问元素的重要手段,容器都有相应的函数来获取特定的迭代器(此处可以简单理解为指向特定元素的指针)。在 STL 的阶段,我们会对迭代器进行更详细的讲解,现在我们只需要掌握它的基本使用即可。
begin 函数返回首迭代器(指向首个元素的指针);
end 函数返回尾后迭代器(指向最后一个元素的后一位的指针)
如指针一样,迭代器也有其固定的形式。
// 某容器的迭代器形式为 容器名::iterator
// 此处 auto 推导出来 it 的类型为 string::iterator
auto it = str.begin();
while (it != str.end())
{
cout << *it << " ";
++it;
}
cout << endl;