为了解决 C 语言中字符串处理的缺陷,并提供更安全、高效、易用的字符串操作方式 所以c++委员会在std标准命名空间里面创建一个字符串类string 在类中实现了很多的功能可以让我们直接使用
大概如下图结构

然后在string类中写了非常多的成员函数 运算符重载等对外实现了大量功能的接口
string类对象的常见构造

test

赋值重载

test

如下图 在定义的时候直接赋值这样不是调用了赋值重载 右边的char类型的x是先要通过string类的构造函数隐式转换为string类类型 再通过上述的赋值重载进行赋值 但是构造函数没有一个字符的构造函数 就报错了

通过构造函数和赋值重载可以发现 功能设计的时候有些冗余了 很多功能都是重的 char*类型也能隐式转换string 其实是为了兼容c
string类对象的容量操作

这些都是string类的成员函数
size和length功能都是返回字符的个数 只不过最开始是用的length 后来发现如在树那块等用length来表示就不合理了 用size来表示比较合理 但是也没有吧length给删掉 建议使用size
capacity 返回容量
max_size 用于返回字符串理论上的最大长度 这个和系统内存 实现限制都有关

resize函数用于调整字符串的大小(长度)
若n小于当前字符串长度,会截断字符串,保留前n个字符。
若n大于当前字符串长度,会在字符串末尾添加值为0的char类型字符,使字符串长度达到n。
第二个参数可以为字符类型 如果n大于字符串长度的话就会以该字符填充
如下 第二个 默认的字符0在字符串中是结束标准 cout不会打印出来

empty
检测字符串释放为空串,是返回true,否则返回false
clear
清空有效字符 不改变底层空间大小

npos
在 C++ 中,string::npos 是 string 类的一个静态常量成员,表示“不存在的位置”或“无效的索引”。它通常用于字符串搜索、子字符串操作等场景,表示未找到匹配项或超出有效范围。
由于 size_t 是无符号类型,-1 会被转换为它的最大值
string类对象的访问及遍历操作
重载[]


string类型可以像数组一样用下标访问及进行修改 就是用到了运算符重载 返回了char类型的引用
迭代器
在c++中提供了一些迭代器

迭代器在理解上现在暂时可以看作类型指针一样 但不是真的指针
begin()相当于指向的就是第一个位置 end()相当于指向的是最后一个字符的后一个位置 也就是 /0

所有的容器都可以用类型这种方式进行访问
反向迭代 rbegin()指向倒数第一个位置 rend()指向第一个字符的前一个位置 但是里面ii还是++的方式 也证明了不是指针

迭代器有四种 根据带不带const 和带不带 reverse划分
auto
auto本来是一个已经被废弃掉的关键字 c++11中对其进行重定义 使其变废为宝
现在auto 如int double 一样 是类型 不过它可以自动识别是什么类型
如刚刚的迭代器或者int double 等都可以自动识别

其实 auto 基本没什么用到的地方也 就是在简化代码方面有些用处 如一个类型很长 如std::string::iterator等等 写起来比较麻烦就可以用auto 当然随之代码可读性降低了
auto可以做返回值(不建议 如果多层调用都是auto 不知道参数是什么类型) 不可以作为函数的形参类型 也不可以作为数组的类型
遍历string方式
1. 通过重载过的[]进行下标访问
2.迭代器方式
3.范围for

范围for
在c++11出现 用于需要全部遍历
for循环后的括号由冒号“ :分为两部分:第一部分是范围 内用于迭代的变量,第二部分则表示被迭代的范围
底层用到的其实就是迭代器 自动赋值,自动迭代,自动判断结束

要注意 如果要改变内容 引号左边的内容要引用

string类对象的修改操作
插入

push_back 一次只能尾插一个字符
如下图 不断尾插c 当空间不够的时候会自动扩容(在string类中已经写好 后面的中间插入其实都会自动扩容和移动位置)
扩容空间问题
对于vs下的 初始的容量为15 其实空间为16(有一个/0占一个空间)容量只算能存的空间为15 空间不够时第一次扩容 扩容到原来的2倍为31其实是16*2然后/0占一个 之后都是1.5倍的扩容

为什么vs下第一次是15呢 其实在string中 有一个是存放16个字符的数组 一个字符指针 当字符小于等于16的时候就用第一个_Buf来存储 当超过16的时候就用_Ptr来存储


对于linux下的 gcc编译器初始没有空间 第一次开一个空间 之后每次为上一次二倍的方式扩容

这时候可以用到以下函数reserve
用于提前分配内存,以优化字符串操作时的性能,避免频繁的内存重新分配

如下 这样就避免了扩容的消耗

这为什么是112个空间呢呢 其实是因为对齐原则
既然reserve会自动预留空间 如果预留的空间小于容量会缩容吗
对于vs来说

当预留空间小于size和大于size小于capacity的情况下都不会扩容 而对于大于capacity的情况会进行扩容
而对于linux下的gcc而言

当预留空间小于size时候容量如果此时大于size 容量会缩小到和size一样大 当预留空间大于size 小于容量时会扩容 当大于capacity会扩容

append
用于在一个字符串尾部插入字符 同样也是为了c的兼容搞了一堆char*的还

重载+=

+=test

重载的+= 其实就可以不用push_back 和append了基本 很多设计的确实有些麻烦了
insert

insert相较于上面的插入主要区别在于可以选择插入的位置
inserttest

删除
erase

第一行的 第一个参数时删除开始的位置 默认缺省值为第一个位置 第二个参数为删除的长度 默认缺省值全删 都不写的话就会全部删掉
erasetest

可以看到删除在vs下也并不会缩容
替换
replace

test

如果要让一个字符串中的空格全部替换为*** 我们可以要到find结合replace来实现
查找
find


第二个参数没有默认从第一个位置开始找 如果没有找到返回npos (最大值)
如下 用find和replace就可以解决刚刚的把所有的空格都替换为***的问题
但是还有个问题 对于replace如果是一个位置替换为多个字符 其实会进行将右边数据整体后移 当多个位置替换为少个后面的又会整体左移 如果有很多的空格 这样会有很多的消耗

另一种方法 再创建一个字符串ss 遍历s4不是空格ss就加该字符 是字符ss+=***

rfind

类似于find rfind是从后往前找
可以用于找文件的后缀 不过还需要用到一个函数 substr

用于返回字符串的部分子串 第一个参数没有默认缺省值从0开始 第二个参数没有默认缺省值nops到字符串的末尾
用rfind和substr就可以解决 找文件后缀的问题了 用find如果前面文件名有.就出问题了


这和find的区别在于可以同时对好几个字符同时处理 如下图
找到abcdef中的任何一个都会返回size_t类型 然后替换为*

对应的其他也都差不多 last就是从后开始找 加了not就是不是里面内容的返回

c_str()

该函数返回一个指向以空字符结尾的字符数组的指针,这个字符数组存储了与 string 对象相同的字符序列。const 关键字表示返回的指针指向的内容是只读的,不能通过这个指针修改字符串内容。
生命周期问题:返回的C风格字符串指针的生命周期与 string 对象相关联。如果 string 对象被修改或销毁,那么之前通过 c_str() 获取的指针将不再有效,继续使用该指针可能会导致未定义行为。
只读性:由于返回的指针是 const char* 类型,不能通过该指针修改字符串内容。如果需要修改字符串,应该直接操作 string 对象。

为了兼容c而存在 接收到之后不能自己改变 会随着原来string中字符串的改变自动改变 生命周期也和原来string字符串相同
string大小

从上述图片知道 不管string类型有多次 sizeof算的字节数都是40个 (当然这和编译器及x86 x64都有关)
这其实是 16+8+8+8所得到的
之前提到了 在vs下string类里会有一个char ar [16] 这样的数组 和一个 char* ar2类型的指针 当字符小于16存在数组中 大于16的时候存在指针当中
这里的数组占了16个字节 x64下指针占了8个字节 此外还有size_t类型的size和capacity分别占了8个字节 所以一共占了40个字节
当换成x86下 就是16+4+4+4wield28个字节了

getline

对于cin来说 当读取到空格或者是换行都会结束 所以无法往s1中直接输入空格

使用getline的方式就可以解决了

getline还可以有第三个参数 如果第三个参数写了 那么会一直读取 直到读取到这个参数然后结束
如果没有的话就默认读取到换行结束

这里第三个参数为* 则会一直读取直到读取到*为止 否则会一直读取输入的数据

1116

被折叠的 条评论
为什么被折叠?



