c++ (8) string类
1、string的介绍
1.1学习string的意义
在我看来学习某个东西一定是要有意义的,那么这里string的作用和功能都相当的强大,对比起我们以前学习的c语言简直不知道方便了多少倍。
string
类是因为它简化了字符串的操作,避免了传统字符数组的繁琐和潜在错误,提供了动态内存管理、丰富的成员函数(如查找、替换、拼接等),并支持与C++标准库的无缝集成,使得字符串处理更加高效、安全和便捷。
1.2C语言中的字符串
1.3string类
从实际的角度上来说,string是不属于STL的范畴的,因为历史的缘故,string比STL更早出现,但是使用的时候我习惯于把它当做STL来理解。
它本质上是由 typedef而来 ,是由类模版basic_string<char>实例化而来,用来记录一些字符。
既然是一个类,那么它就有成员变量、成员函数,操作符重载和六大默认构造 接下来,将要从这几个角度思考问题。
2、string的默认函数
2.1构造函数
通过查表我们可以得到库里面给我提供了这些,我们一个一个来解析
string(): 空字符串构造函数(默认构造函数)
构造一个长度为零个字符的空字符串
string(const string&s) 拷贝构造,参数就是一个const string类
string(const char* s)
string(const char* s,size_t n) 从 s 指向的字符数组中复制前 n 个字符
string (const basic_string& str, size_type pos, size_type len = npos);
复制从字符位置 pos 开始并跨越 len 字符的 str 部分
npos
std::string::npos
是一个 std::string::size_type
类型的常量,表示一个无效的位置。它通常被定义为一个大整数 。
简单分析 size_t是无符号的数,-1的补码为 11111111111111111111111111111111,所以对于无符号数来说他的值为INT_MAX就是int类型最大值。
npos
是一个特殊的静态常量,表示一个无效的位置或“未找到”的值。它通常用于字符串操作中,表示某个操作没有找到预期的结果。
2.2析构函数
表中没有关于析构的实现,所以,我们不用注意这一点,毕竟在销毁时,它会自动调用,所以不必在意
3、运算符重载
3.1赋值运算符重载
这里库里面给了我们三个,其实就是调用我们上面的拷贝构造。
3.2流插入符与流输出符
<< >>使用这两个操作符,可以对string进行io流操作这个很简单
3.3 [ ] 的重载
返回值就是相应位置的元素,提高代码可读性。
3.4 + 的重载
直接在string后面加上后面那个string的元素,值得注意的是当目标对象空间不够的时候会自动扩容。
3.5关系的重载
1.等与不相等:两个字符串完全一样,字符数量,与字符一 一相等,不相等就是它的反向逻辑
“abcdef” 与 "abcdef"相等 “aaaaaa”与“bbbbbb”不相等
2.大于 :第一个字符串大于第二个字符串:两个字符串中,第一个不相等的字符,左边的字符大于右边字符的Ascll值,还一种情况是,左右两边的字符串Ascll值一直相等,但是,左边字符串更长
"abcdef"大于"abcdea" f的Ascll值大于a
“ abcde”大于" abcd" 左边字符串比右边长
其实介绍完这两个,其他的就不用介绍了
3. 小于:不就是 大于等于取反吗?
4.大于等于:不就是大于和等于或一下
5.小于等于:就是大于取反
4、内部数据查看的函数
4.1 size和length
这里size和length的作用是一样的,都是返回元素的个数。因为历史原因,string问世的时候还没STL,所以先有的length,后来出现STL为了统一出现了size。
4.2 max_size就是返回最大值
4.3 capacity就是容量。
4.4 clear就是清理string
4.5 reserve是扩容
需要注意的是如果输入的空间比原来得大,那就一定会扩容,但是如果小与的话就不一定会缩容。
5、string的增删查改
5.1 append
(1) string
附加 str 的副本。
(2) substring
附加 str 的子字符串的副本。substring 是 str 的一部分,从字符位置 subpos 开始并跨越 sublen 字符(或者直到 str 的末尾,如果 str 太短或 sublen 为 string::npos)。
(3) c-string
追加由 s 指向的以 null 结尾的字符序列(C 字符串)形成的字符串的副本。
(4) buffer
在 s 指向的字符数组中追加前 n 个字符的副本。
(5) fill
追加字符 c 的 n 个连续副本。
(6) range
按相同的顺序附加范围 [first,last) 中的字符序列的副本。
(7) 初始化器列表
按相同的顺序附加 il 中每个字符的副本。
5.2 尾插push_back()
尾插就顾名思义喽,比较简单就不做解释了。
5.3替换assign
具体功能就是
示例:
5.4 插入insert()
这里提供了很多种方法,但实际我们只要掌握几种就好了,之后如果遇到不会的可以查表解决。
值得注意的是,insert的时间复杂度是O(n)。
5.5 删除erase()
可以传要删除的位置和长度,也可以传迭代器。
5.6 替换replace()
示例:
6、迭代器遍历string
6.1 迭代器
迭代器类似于指针,指针只是指向一个变量,但是迭代器是指向一个自定义类型,他们都是用来访问内容的,下面就可以使用迭代器去遍历string类
直接看文档,一共八个迭代器
先看begin和end
他们是一个获取首位置,以获取尾位置,对于end来说它获取的位置为有效位的下一个
end: Returns an iterator pointing to the past-the-end character of the string.
看代码如何遍历:
再看 rbegin() 以及 rend()
rbegin()是返回最后一个有效位置,而rend是返回第一个有效位置之前的位置。注意他们是反向迭代器,所以移动的方向也会反向。
那么看代码吧!!
再看 cbegin() cend(),他们是常量迭代器,不能修改字符串的内容。当然前面的非常量迭代器是可以修改string的。我们这里长话短说
string ::const_iterator it=a.cbegin();
同理crend() 以及 crbegin()的道理是一样的,他们只是反向的常量迭代器
string ::const_reverse_iterator it=a.crbegin();
6.2 auto和范围for
auto关键字
#include<iostream>
using namespace std;
int func1()
{
return 10;
}
// 不能做参数
void func2(auto a)
{}
// 可以做返回值,但是建议谨慎使用
auto func3()
{
return 3;
}
int main()
{
int a = 10;
auto b = a;
auto c = 'a';
auto d = func1();
// 编译报错:rror C3531: “e”: 类型包含“auto”的符号必须具有初始值设定项
auto e;
cout << typeid(b).name() << endl;
cout << typeid(c).name() << endl;
cout << typeid(d).name() << endl;
int x = 10;
auto y = &x;
auto* z = &x;
auto& m = x;
cout << typeid(x).name() << endl;
cout << typeid(y).name() << endl;
cout << typeid(z).name() << endl;
auto aa = 1, bb = 2;
// 编译报错:error C3538: 在声明符列表中,“auto”必须始终推导为同一类型
auto cc = 3, dd = 4.0;
// 编译报错:error C3318: “auto []”: 数组不能具有其中包含“auto”的元素类型
auto array[] = { 4, 5, 6 };
return 0;
}
那auto在这里好像没有明显的作用哈,那么我们看看当类名很复杂的情况下,它的作用就明显了:
#include<iostream>
#include <string>
#include <map>
using namespace std;
int main()
{
std::map<std::string, std::string> dict = { { "apple", "苹果" },{ "orange",
"橙子" }, {"pear","梨"} };
// auto的用武之地
//std::map<std::string, std::string>::iterator it = dict.begin();
auto it = dict.begin();
while (it != dict.end())
{
cout << it->first << ":" << it->second << endl;
++it;
}
范围for
int main()
{
for (auto& e : array)
e *= 2;
for (auto e : array)
cout << e << " " << endl;
string str("hello world");
for (auto ch : str)
{
cout << ch << " ";
}
cout << endl;
return 0;
}
范围for有三个自动:
1、自动赋值给e
2、自动array++
3、自动判断停止
全是自动,看起来很高级哈,但其实底层就是迭代器,如果自己定义一个类不写迭代器就会报错
如果要修改数据可以这样:
for(auto& e : array)