🔥个人主页:guoguoqiang. 🔥专栏:我与C++的爱恋
朋友们大家好啊,本节我们来到STL内容的第一部分:string类接口函数的介绍
1.string类的认识
给大家分享一个c++文档
https://legacy.cplusplus.com/
- 字符串 string 是表示字符序列的类
- 标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作
单字节字符字符串的设计特性。 - string类是使用char(即作为它的字符类型,使用它的默认char_traits和分配器类型(关于模板的更多信
息,请参阅basic_string)。 - string类是basic_string模板类的一个实例,它使用char来实例化basic_string模板类,并用char_traits
和allocator作为basic_string的默认参数(根于更多的模板信息请参考basic_string)。 - 注意,这个类独立于所使用的编码来处理字节:如果用来处理多字节或变长字符(如UTF-8)的序列,这个
类的所有成员(如长度或大小)以及它的迭代器,将仍然按照字节(而不是实际编码的字符)来操作。
总结: - 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—str来构造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的缺省值,如果不给值,默认给npos,会遍历到字符串末尾。
了解一下npos
npos是一个无符号常量整数-1,无符号整数-1即为整形的最大值2^32-1
用法:
string s1("hello world");
string s3(s1, 5, 3);
string s4(s1, 5, 10);
string s5(s1, 5);
cout << s1 << endl;
cout << s3 << endl;
cout << s4 << endl;
cout << s5 << endl;
输出结果:
hello world
wo
world
world
string(const char*s,size_t n);
函数的功能是拷贝字符串的前n个字符
string(size_t n,char c);
这个函数的功能就是用n个字符c来构造字符串,用法:
2.2 对string对象的遍历和修改
对于string遍历使用[]遍历最为方便
函数的功能是返回pos位置的字符
int main() {
string s1("hello world");
for (int i = 0; i < s1.size(); i++) {
cout << s1[i] << " ";
}
cout << endl;
return 0;
}
字符串长度通过s.size()来表示。
operator[]是一个重载的操作符,用于直接访问和修改字符串中特定索引位置的字符
char& operator[] (size_t pos);
返回的为引用,意味着我们还可以对这个位置进行修改。
例如:
int main() {
string s1("hello world");
for (int i = 0; i < s1.size(); i++) {
s1[i]++;
cout << s1[i] << " ";
}
cout << endl;
return 0;
}
这里我们发现还有第二种重载方式:
const char& operator[] (size_t pos) const;
const定义的对象是只读的,不能对其进行修改
迭代器iterators
迭代器的作用是用来访问容器(用来保存元素的数据结构)中的元素,所以使用迭代器,我们就可以访问容器中里面的元素。这和访问数组这个序列的指针一样,因为数组范围内的指针就是迭代器的一种。
int main() {
string s1("hello world");
string::iterator it1 = s1.begin();
while (it1 != s1.end()) {
cout << *it1 << " ";
++it1;
}
cout << endl;
return 0;
}
begin作用是返回第一个有效位置的迭代器,end是返回最后一个元素的下一个位置,也就是/0的位置。
虽然我们习惯使用下标来访问,但是有时候只能只能使用迭代器来访问(迭代器的访问范围更广泛),比如后面的list部分。所以迭代器才是最重要的方式。
反向迭代器
它返回的是字符串末尾的迭代器,我们用这一组迭代器可以实现逆序遍历
int main() {
string s1("hello world");
string::reverse_iterator it1 = s1.rbegin();
while (it1 != s1.rend()) {
cout << *it1 << " ";
++it1;
}
cout << endl;
return 0;
}
还有const版本
const_iterator begin() const;
int main() {
string s1("hello world");
string::const_iterator it1 = s1.begin();
while (it1 != s1.end()) {
//(*it1)++; //如果修改会编译报错
cout << *it1 << " ";
++it1;
}
cout<<endl;
return 0;
}
对const字符串进行遍历,const_iterator是只读的,不可写
范围for
string s1("hello world");
for (auto e : s1)
{
cout << e << " ";
}
cout << endl;
范围for本质就是迭代器
2.3 string类对象的容量操作
size
size的功能是返回字符串长度
capacity
void func2()
{
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;
}
}
}
通过上述函数来看一下它的扩容机制
我们发现第一次是以2倍扩容,后面都是1.5倍扩容。
clear
clear作用是清空有效字符,但它对capacity没有影响
void func3() {
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(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserver不会改变容量大小。
当你知道将要在字符串中存储具体数量的字符时,使用reserve可以减少因反复增加字符串大小而导致的多次内存分配和数据复制,从而提高性能。(提前开好,减少扩容,提高效率)
扩容可能会开辟新的空间,使用reserve我们就可以减少扩容
string s;
s.reserve(100);
cout << s.capacity() << endl;
reserve的调用是一个请求,所以他申请的空间可能大于你要的空间,但不会小于。(g++中是刚好等于你要的空间)
reserve不会进行缩容,比当前capacity大才会进行扩容
resize
resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。
注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。
如果个数不变,resize不会对字符串进行任何修改。
void func5() {
string str("hello");
str.resize(10, 'x');//结果 helloxxxxx
str.resize(2); //结果 he
str.resize(5); //结果 hello
cout << str << endl;
}
resize直接修改字符串本身,如果你增长字符串并且不指定填充字符则填充空字符’\0’ ,如果减小字符串长度,被移除的字符就被丢弃,而且无法恢复。
2.4 string类对象的修改操作
push_back
在字符串后面尾插字符
string s("abcdef");
s.push_back('e');
cout<<s<<endl;//abcdefe
append
在字符串后追加一个字符串
void test_string10() {
string s("hell");
s.push_back('o');
cout << s << endl;
s.append("world");
cout << s << endl;
}
append也可以插入string,或者插入string的部分。还可以插入n个字符
void test_string11() {
string s("hell");
string s1("o world!");
s.append(s1);
cout << s << endl;
}
void test_string11() {
string s("hell");
string s1("o world!");
s.append(s1,0,2);
cout << s << endl;//hello
}
还可以插入字符串的迭代区间
void test_string12() {
string s("hell");
string s1("o world!");
s.append(s1.begin(),s1.end());
cout << s << endl;
}
如果在这里我们不想要感叹号可以这样追加:
void test_string12() {
string s("hell");
string s1("o world!");
s.append(s1.begin(),--s1.end());
cout << s << endl;
}
operator+=
operator+=十分方便,我们可以直接追加一个string对象,或者一个字符串,或者一个字符。
insert和erase
insert可以在指定位置插入数据。
void test_string13() {
string s("hello");
s.insert(0, "xxx");
cout << s << endl;
}
erase
从pos位置开始删除,这里pos给的缺省值,如果不传参,则全部删除,len的缺省值为npos,如果len大于剩余字符长度(_size-pos),也会全部删除掉
replace
对string对象内容进行替换
void test_string14() {
string s("hello ");
s.replace(6,1, "world");//把下标为6的那个字符修改为world字符串
cout << s << endl;
}
find
find用于搜索字符串中第一次出现的指定子字符串或字符的位置。如果找到了指定的子字符串或字符,find会返回它开始的位置的索引;如果没有找到,它会返回一个特殊的常量std::string::npos(这个是无效的位置),表示未找到任何匹配。
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) {
printf("找到了子字符串 \"world\"");
}
- 从指定位置开始搜索
string str = "Hello, world! world!";
size_t pos = str.find("world", 8); // 从索引8开始搜索
if (pos != string::npos) {
printf("找到了第二个 \"world\"");
}
find函数可以搜索字符串中的内容,是处理字符串时常用的功能之一
本节内容到此结束!感谢大家阅读!!