🔥个人主页:Quitecoder
🔥专栏:c++笔记仓
朋友们大家好啊,本节我们来到STL内容的第一部分:
string
类接口函数的介绍
目录
- 1.string类的认识
- 2.常见接口讲解
- 2.1 string类对象的常见构造
- 2.2 对string对象的遍历和修改
- 2.3 string类对象的容量操作
- 2.4 string类对象的修改操作
- 注意事项:
1.string类的认识
给大家分享一个c++文档库:
https://legacy.cplusplus.com/
字符串类是代表字符序列的对象 |
标准字符串类为这类对象提供了支持,其接口类似于标准字节容器的接口,但增加了专门用于操作单字节字符字符串的特性 |
通过下面这串代码:
typedef basic_string<char> string;
对应文档内容:
字符串类是basic_string
类模板的一个实例化,它使用char
(即字节)作为其字符类型,并使用默认的char_traits
和分配器类型
请注意,这个类独立于使用的编码处理字节:如果用来处理多字节或变长字符(如UTF-8)的序列,这个类的所有成员(如length
或size
),以及其迭代器,仍将以字节(而非实际编码的字符)的方式操作
简单总结:
- string是表示字符串的字符串类
- 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作
- string在底层实际是:basic_string模板类的别名,
typedef basic_string<char,char_traits, allocator> string;
- 不能操作多字节或者变长字符的序列
在使用string类时,必须包含#include头文件以及using namespace std;
2.常见接口讲解
2.1 string类对象的常见构造
构造函数
🔥string()
这个函数的功能是构建一个空字符串,也是默认构造
🔥string(const char* s)
用C-string来构造string类对象
用法如下:
string s1("hello world");
🔥string (const string&s)
拷贝构造函数,用法:
string s1("hello world");
string s2(s1);
🔥string (const string& str, size_t pos, size_t len= npos);
我们来看文档对这一部分的讲解:
拷贝从pos位置开始,向后len长度,如果超过剩余长度,则遍历到字符串的末尾
注意,这里有个npos
的缺省值,如果我的len
给的nops
,也会遍历到字符串末尾,简单了解一下npos
npos
是一个无符号常量整数-1,无符号整数-1即为整形的最大值232-1
用法:
string s1("hello world");
string s2(s1);
string s3(s1, 5, 3);
string s4(s1, 5, 10);
string s5(s1, 5);
cout << s1 << endl;
cout << s2 << endl;
cout << s3 << endl;
cout << s4 << endl;
cout << s5 << endl;
打印结果如下:
hello world
hello worldwoworldworld
注意:我们这里直接进行对对象的打印,是因为string类已经完成了对流运算符的重载
🔥string(const char* s, size_t n);
此函数的功能是拷贝字符串的前n个字符
string s("hello world", 5);
cout << s << endl;
🔥string (size_t n, char c);
这个函数的功能就是用n个字符c来构造字符串,用法:
string s(10,'x');
cout << s << endl;
打印结果:
2.2 对string对象的遍历和修改
现在有一个字符串,我想打印它的每个字符,或者对每个字符进行加一操作,我该如何遍历呢?
🔥operate[ ]
函数的功能是返回pos位置的字符
string s1("hello world");
for (int i = 0; i < s1.size(); i++)
{cout << s1[i] << " ";
}
cout << endl;
这里,字符串长度我们用s1.size()
来表示,后续进行讲解
operator[]
是一个重载的操作符,用于直接访问和修改字符串中特定索引位置的字符
这个地方与我们数组访问相似,但本质不同,数组是对指针的解引用,而这里是对函数的调用
char& operator[] (size_t pos);
返回pos位置的引用,意味着我们除了获取pos位置的字符,还可以对这个位置进行修改
例如:
string s("abcde");
for (int i = 0; i < s.size(); i++)
{s[i]++;
}
cout << s << endl;
这里我们发现还有第二种重载方式:
const char& operator[] (size_t pos) const;
const定义的对象是只读的,不能对其进行修改
🔥迭代器Iterators
迭代器是一种允许程序员遍历容器(如数组、链表、树等数据结构)中的元素的对象,而无需了解容器的内部结构
我们来看它的使用方法再进行理解:
string s1("hello world");
string::iterator it1 = s1.begin();
while (it1 != s1.end())
{cout << *it1 << " ";it1++;
}
迭代器是定义在string类域里面的
迭代器的工作原理类似于指针:它指向容器中的某个元素,并提供了访问该元素的方法。通过迭代器,可以读取它指向的元素的值,有时也可以修改这个值(取决于迭代器的类型)。迭代器可以向前或向后移动(在支持的容器中),从而遍历容器中的所有元素
begin作用是返回第一个有效位置的迭代器,end是返回最后一个元素的下一个位置,也就是/0
的位置
我们再看代码,可能这串代码并不如上述的操作符重载进行对字符串的访问方便,但是迭代器的用处是非常广泛的,比如后面学到链表部分,就无法用操作符
[]
进行访问,所以迭代器才是最重要的方式
🔥反向迭代器rbegin()和rend()
它返回的是字符串末尾的迭代器,我们用这一组迭代器可以实现逆序遍历
体会一下它的用法:
string s1("hello world");string::reverse_iterator rit = s1.rbegin();while (rit != s1.rend()){cout << *rit << " ";++rit;}cout << endl;
除了这种版本还有const
版本
const_iterator begin() const;
const string s1("hello world");
string::const_iterator it1 = s1.begin();
while (it1 != s1.end())
{cout << *it1 << " ";it1++;
}
对const字符串进行遍历,const_iterator
是只读的,不可写
🔥范围for()
string s1("hello world");
for (auto e : s1)
{cout << e << " ";
}
cout << endl;
自动取容器中的数据自动进行遍历,我们可以调试一下看一下它的本质
所以范围for本质就是迭代器,我们后面模拟实现再进行讲解
2.3 string类对象的容量操作
🔥size
size的功能是返回字符串长度,用法如下:
string s1("hello world");
cout << s1.size() << endl;
🔥capacity
我们可以用一串代码来看一下它的扩容机制
void fun7()
{string s;size_t sz = s.capacity();cout << sz << endl;for (int i = 0; i < 100; i++){s.push_back('a');if (sz != s.capacity()){sz = s.capacity();cout << "容量:" << sz << endl;}}
}
构造一个空字符串,不断进行尾插来扩容:
第一次以二倍扩容,后面以1.5倍进行扩容
🔥clear
clear作用是清空有效字符,但它对capacity没有影响
string s("hello world");
size_t sz = s.capacity();
cout << s << endl;
cout << sz << endl;
s.clear();
cout << s << endl;
cout << s.capacity() << endl;
🔥empty
检测字符串释放为空串,是返回true,否则返回false
🔥reserve
reserve
被用来预分配内存以存储一定数量的字符,从而提高字符串操作的效率。这个函数允许你指定一个期望的容量(以字符数计),std::string
对象会确保它有足够的空间来存储至少这么多字符而无需进行进一步的内存分配
具体来说,当你知道将要在字符串中存储大量字符时,使用reserve
可以减少因反复增加字符串大小而导致的多次内存分配和数据复制,从而提高性能
扩容可能会开辟新的空间,使用reserve我们就可以减少扩容
string s;
s.reserve(50);
cout << s.capacity() << endl;
reserve
的调用是一个请求,而不是命令,这意味着实际的容量可能大于或等于请求的容量,具体取决于标准库的实现细节和内存分配策略
string s("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
cout << s.capacity() << endl;
s.reserve(10);
cout << s.capacity() << endl;
reserve不会进行缩容,比当前capacity大才会进行扩容
🔥resize
reserve
用来改变容量,resize
改变字符串的长度,并可以初始化新添加的字符(如果增加了长度)。这个函数根据传递给它的新大小参数调整字符串的长度,以下是 resize
函数的不同使用情况和它们的效果:
-
增加长度:
- 当新的大小大于当前字符串的长度时,
resize
会增加字符串的长度,并将新增加的位置填充指定的字符,或者如果没有提供字符,则填充默认字符(即空字符 ‘\0’) - 示例:
string str = "Hello"; str.resize(10, 'x'); // 结果:Helloxxxxx
- 在这个例子中,
str
被扩展到长度 10,新位置被填充为 ‘x’。
- 当新的大小大于当前字符串的长度时,
-
减少长度:
- 如果新的大小小于当前字符串的长度,
resize
会截断字符串,只留下从开头开始的新长度的字符。 - 示例:
string str = "Hello, World!"; str.resize(5); // 结果:Hello
- 这里
str
被缩短到前 5 个字符,即 “Hello”
- 如果新的大小小于当前字符串的长度,
-
不改变长度:
- 如果新的大小等于当前字符串的长度,
resize
实际上不会对字符串做任何修改。 - 示例:
string str = "Hello"; str.resize(5); // 结果:Hello
- 在这个例子中,
str
保持不变
- 如果新的大小等于当前字符串的长度,
使用注意:
resize
直接修改字符串对象本身,不返回新的字符串- 如果你增加字符串长度并且不指定填充字符,则填充空字符
‘/0’
- 减少字符串长度时,被移除的字符将被丢弃,并且无法恢复
- 使用
resize
能有效地控制字符串的长度,对于控制内存使用和避免越界访问特别有帮助
2.4 string类对象的修改操作
🔥push_back
在字符串后尾插字符c
string s("abcd");
s.push_back('e');
cout << s << endl;
打印结果:
abcde
🔥append
在字符串后追加一个字符串
string s("abcd");
s.push_back('e');
cout << s << endl;
s.append(" higkl");
cout << s << endl;
append也可以插入string,或者插入string的部分。还可以插入n个字符
string s1("hello ");
string s2("world");
s1.append(s2);
cout << s1 << endl;
也可以插入字符串的迭代器区间
string s1("hello ");
string s2(" world ");
s1.append(s2);
cout << s1 << endl;
比如上述代码,我不需要world前面和后面的空格,我可以这样追加:
string s1("hello ");
string s2(" world ");
s1.append(++s2.begin(),--s2.end());
cout << s1 << endl;
🔥operate+=
operate+=
使用起来就非常方便了,我们可以直接追加一个string对象,或者一个字符串,或者一个字符
🔥insert和erase
insert功能也非常多,主要就是在指定位置插入字符串,我们来看几个示例:
string s1("abcde");
s1.insert(0, "xxx");
cout << s1 << endl;
在头部插入
其他功能也十分类似,我们通过文档也可以自己写出来
string& erase (size_t pos = 0, size_t len = npos);
从pos位置开始删除,这里pos给的缺省值,如果不传参,则全部删除,len的缺省值为npos,我们前面已经提到过,如果len大于剩余字符长度,也会全部删除掉
🔥replace
对string对象内容进行替换,也有多种功能,我们简单举例:
string s1("abc def ghi");
s1.replace(3, 1, "xx");
cout << s1 << endl;
索引3开始的1个字符替换为字符串"xx"
abcxxdef ghi
🔥find
find
用于搜索字符串中第一次出现的指定子字符串或字符的位置。如果找到了指定的子字符串或字符,find
会返回它开始的位置的索引;如果没有找到,它会返回一个特殊的常量std::string::npos
,表示未找到任何匹配。
find
函数有几个重载版本,允许你在字符串中搜索不同类型的数据,包括单个字符、字符串和字符数组,还可以指定从哪个位置开始搜索
find
函数的常见用法如下:
-
搜索字符:
string str = "Hello, World!"; size_t pos = str.find('W'); if (pos != string::npos) {cout << pos << endl;// 找到了字符 'W' }
-
搜索子字符串:
string str = "Hello, World!"; size_t pos = str.find("World"); if (pos != string::npos) {// 找到了子字符串 "World" }
-
从指定位置开始搜索:
string str = "Hello, World! World!"; size_t pos = str.find("World", 8); // 从索引8开始搜索 if (pos != string::npos) {// 找到了第二个 "World" }
注意事项:
find
返回的位置索引是基于0的,即字符串中第一个字符的位置索引为0。- 如果
find
没有找到匹配项,它将返回string::npos
。string::npos
是size_t
类型的最大值,用于表示无效的位置 - 使用
find
可以非常方便地检查一个字符串是否包含另一个字符串或字符,以及确定它们的位置
find
函数提供了一种简单而有效的方法来搜索字符串中的内容,是处理字符串时常用的功能之一
本节内容到此结束!感谢大家阅读!!