当前位置: 首页 > news >正文

【c++】STL-string容器的使用

hello~ 很高兴见到大家! 这次带来的是C++中关于STL-string容器的使用这部分的一些知识点,如果对你有所帮助的话,可否留下你的三连呢?
个 人 主 页: 默|笙

在这里插入图片描述

文章目录

  • 一、STL
    • 1.1 什么是STL
    • 1.2 STL的版本
    • 1.3 STL的六大组件
  • 二、string类及其使用
    • 2.1 成员常量
    • 2.2 可以默认生成的特殊成员函数
      • 1. 构造函数
      • 2. 析构函数
      • 3. 赋值重载函数
    • 2.3 迭代器成员函数
      • 1.正向迭代器(begin从前往后遍历):
      • 2.反向(reverse)迭代器(rbegin从后往前遍历):
    • 2.4 遍历
      • 2.4.1 下标 + []
      • 2.4.2 迭代器
      • 2.4.3 范围 for(c++11)
        • 1. auto关键字
        • 2.遍历
    • 2.5 容量相关成员函数
      • 7. *shrink_to_fit():
      • 8. resize(n, c):
      • 9. reserve(n):
    • 2.6 元素访问相关成员函数
      • 1. operator[]:
      • 2. *at(pos):
    • 2.7 修改相关成员函数
      • 1. operator+=:
      • 2. *append():
      • 3. *push_back():
      • 4.*assign():
      • 5.*insert():
      • 6.*erase():
      • 7.*replace:
      • 8.swap():
      • 9.pop_back():
    • 2.8 字符串操作相关成员函数
      • 1. c_str():
      • 2.*data():
      • 3.get_allocator():
      • 4.*copy(s, len, pos):
      • 5.substr(pos, len):
      • 6.find():
      • 7.*rfind():
      • 8.*find_first_of(s/c, pos):
      • 9.*find_last_of(s/c, pos):
      • 10.*find_first_not_of(s/c, pos):
      • 11.*find_last_not_of(s/c, pos):
      • 12.*compare():
    • 2.9 非成员函数
      • 1.*operator+:
      • 2.relational operators:
      • 3.swap(x, y):
      • 4.operator>> 与 operator<<:
      • 5.getline(string)

一、STL

1.1 什么是STL

STL(Standard Template Library,标准模板库) 是 C++ 标准库的重要组成部分,提供了通用的模板类和函数,用于实现数据结构和算法。它的核心思想是泛型编程,通过模板(Template)让代码具备高度复用性。

1.2 STL的版本

  1. HP版本:STL首个实现版本,开源,其他版本通常都是基于此版本来实现的。
  2. P.J.版本:继承自HP版本,不开源,可读性低,符号命名比较怪异,被Windows Visual C++采用。
  3. RW版本:继承自HP版本,不开源,可读性一般,被C+ + Builder 采用。
  4. SGI版本:继承自HP版本,开源,可读性高,被GCC(Linux)采用。

1.3 STL的六大组件

在这里插入图片描述

  1. 容器:用于存储和管理数据的类模板
  2. 算法:一系列用于处理容器中元素的函数模板
  3. 迭代器与指针类似,用于遍历容器中的元素,是容器与算法之间沟通的桥梁。
  4. 仿函数:通过重载函数调用运算符 () 实现,可像函数一样调用的类或结构体(不是真函数,它是对象,但行为像函数),能用于自定义算法的行为。
  5. 配接器:也叫适配器,用于修改容器、迭代器或仿函数的接口,使其符合特定需求 。
  6. 空间配置器:负责容器的内存分配和释放,管理容器的内存资源。

二、string类及其使用

string

定义: std :: string是c++标准库提供的动态字符串类(位于头文件 < string> 中),它封装了对字符序列的底层操作,以成员函数和运算符重载为用户提供了一套安全、便捷的接口。

在这里插入图片描述

  1. 可以将其理解为一个管理字符数组的顺序表
  2. string 实际上是 basic_string< char>此类型的别名,是basic_string模板char类型的实例化版本。
  • 使用的时候包含头文件< iostream>,后进行命名空间的展开 using namespace std; 。
  • 有很多接口都不常用,不需要我们去记忆,在需要使用的时候动手去查一查就行,目录里标注星号的一般没那么重要。string<—

2.1 成员常量

在这里插入图片描述

  1. 它是一个静态成员常量值,npos 的值被设置为无符号整数(size_t)的最大值
  2. 当此值用作 string 成员函数中的 len(长度参数) 时,表示直至这个字符串的末尾
  3. 作为返回值,它通常用于表示未找到匹配项
  4. 这个常量被定义为数值 -1,但由于 size_t 是无符号整数类型,因此该值实际上是该类型所能表示的最大可能值。
  • -1 的补码被无符号整数类型解析为最大值

2.2 可以默认生成的特殊成员函数

在这里插入图片描述

1. 构造函数

在这里插入图片描述

  1. 默认构造函数:构造一个长度为0个字符的空字符串。
  2. 拷贝构造函数:以 str 为蓝本,拷贝构造一个字符串。
  3. *子串构造函数:以 str 为蓝本,从索引为 pos 的字符起,拷贝 len 个字符,如果没有传实参给 len ,将会使用默认值 npos。
  1. 若 len 的值超过剩余长度(比如默认值 npos),则截断至末尾
  2. 若 pos 越界时,构造函数会抛出异常,不会静默处理。
  1. c风格字符串构造:复制指针 s 指向的以’\0’ 结尾的字符串序列(遇到 ‘\0’ 停止)。
  2. *缓冲区构造:复制指针 s 指向的字符串里的前 n 个字符(无论是否有 ‘\0’。
  3. *填充构造函数:用字符 c 的连续 n 个副本填充字符串。
  4. *范围构造函数:按顺序复制迭代器区间 [first, last)(左闭右开)内的所有字符。关于迭代器下文将会讲到,它类似指针但不是指针。
//默认构造
string s1;
cout << "s1:" << s1 << endl;
s1 = "abcdefg";
//拷贝构造
string s2 = s1;//string s2(s1);
//子串构造
string s3(s1, 2);
//c风格
string s4("abc\0defg");
//从缓冲区
string s5("abc\0defg", 6);
//填充
string s6(5, 'a');
//范围
string s7(s2.begin(), s2.end());
cout << "s2:"<< s2 << endl;
cout << "s3:" << s3 << endl;
cout << "s4:" << s4 << endl;
cout << "s5:" << s5 << endl;
cout << "s6:" << s6 << endl;
cout << "s7:" << s7 << endl;

执行结果:
在这里插入图片描述

  • 在 std :: string 中,一般情况下不会显式存储’\0’,但在与c风格函数交互时会根据需要进行存储。

2. 析构函数

在这里插入图片描述

析构函数会在 std::string 对象声明周期结束时(如离开作用域,被显式删除),会自动调用析构函数,无需手动干预,仅作了解即可。

3. 赋值重载函数

在这里插入图片描述

string s1("abcdefg");
string s2;
cout << "s2:" << s2 << endl;
//string,自赋值是安全的(s2 = s2)
s2 = s1;
cout << "string:"<< "s2:" << s2 << endl;
//c_string
s2 = "abc\0defg";
cout << "string_c:" << "s2:" << s2 << endl;
//character
s2 = 'a';
cout << "character:" << "s2:" << s2 << endl;

执行结果:
在这里插入图片描述

  • s2 首先得存在,若 s2 不存在就进行赋值操作,编译器会强制调用构造函数,赋值操作将变为初始化操作:string s2 = s1。

2.3 迭代器成员函数

迭代器:在 C++ 中,迭代器(Iterator) 是一种行为类似于指针的对象,它提供了一种统一的方式来遍历和操作容器(如 std::vector、std::list、std::map 等)中的元素,而无需暴露容器的底层实现细节。
意义:

  1. 统一且类似的方式修改容器。在之后的遍历操作中会详细讲解。
  2. 算法脱离具体底层结构,和底层结构解耦。(降低耦合,降低关联性,不用担心底层如何存储,实现)

在这里插入图片描述

1.正向迭代器(begin从前往后遍历):

在这里插入图片描述

  1. begin():返回一个指向字符串首字符(第一个元素) 的非常量迭代器。
  2. end():返回一个指向字符串最后一个字符的下一个位置的非常量迭代器。
  3. *cbegin()和*cend():用于返回正向常量迭代器,相比于begin()/end() 加 const 修饰返回正向常量迭代器,它的语义更明确(好区分),避免意外修改。
string s1 = "abcdefg";
string::iterator it1 = s1.begin();
string::const_iterator it1 = s1.begin();
string::const_iterator it1 = s1.cbegin();

2.反向(reverse)迭代器(rbegin从后往前遍历):

在这里插入图片描述

  1. rbegin():返回一个指向字符串最后一个字符的非常量迭代器(反向开头)。
  2. rend():返回一个指向字符串首字符的前一个位置的非常量迭代器。
  3. *crbegin()和 *crend():用于返回反向常量迭代器,比 rbegin()/rend() 加 const 修饰返回反向常量迭代器更清晰(好区分)安全。
string::reverse_iterator it3 = s1.rbegin();
string::const_reverse_iterator it3 = s1.rbegin();
string::const_reverse_iterator it3 = s1.crbegin();

关于常量迭代器:关于新的类型const_iterator与const_reverse_iterator,它们限制只能对“指向”的元素进行只读访问,而不是指它本身不可修改(const iterator 是本身不可修改)。它们能够很好的保护数据。

在这里插入图片描述

//正向
cout << "正向:" << endl;
string::iterator it1 = s1.begin();
while (it1 != s1.end())
{cout << *it1 << " ";it1++;
}
cout << endl;
//反向
cout << "反向" << endl;
string::reverse_iterator it2 = s1.rbegin();
while (it2 != s1.rend())
{cout << *it2 << " ";it2++;
}

执行结果:
在这里插入图片描述

2.4 遍历

2.4.1 下标 + []

string s1 = "abcdefg";
//下标 + []
for (size_t i = 0; i < s1.size(); i++)
{cout << s1[i] << endl;
}

2.4.2 迭代器

	string s1 = "abcdefg";//迭代器//[begin(), end())string::iterator it1 = s1.begin();while (it1 != s1.end()){(*it1)++;++it1;}cout << s1 << endl;

对于 string 而言,下标 + [] 的确更加直白简单,但是对于其他容器如链表(空间一般不连续),下标 + [] 不再适用,而迭代器适用于一切容器,是容器的主流遍历方式

2.4.3 范围 for(c++11)

1. auto关键字

在c/c++早期,auto的含义是:使用 auto 修饰的变量,是具有自动存储器的局部变量。后来在 c++11中,它被赋予新的含义:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量的类型必须由编译器在编译时期经过推导而得

  1. auto能够自动推导类型。

在这里插入图片描述

  1. auto 和 auto*声明指针类型没有什么不同,但是在声明引用类型时,必须添加 ‘&’

在这里插入图片描述

int x = 10;
int& y = x;
auto z1 = y;//auto推演的是y本身的int类型,而非int&类型
z1++;
cout << y << endl;
auto& z2 = y;//在声明引用类型时,要加上&
z2++;
cout << y << endl;

执行结果:
在这里插入图片描述

  1. 推导过程顺序独立进行:同一行申明多个变量时,这些变量类型必须相同,否则编译器会报错,因为编译器实际只会对第一个变量进行推导,然后用推导出来的类型定义其他变量。
auto x = 5, y = 10;      // 合法:x 和 y 均为 int
auto a = 1, b = 3.14;    // 错误:int 和 double 类型不匹配,编译报错
  1. auto不能作为函数的参数,编译报错,但是可以作返回值。谨慎使用。
  2. auto不能直接用来声明数组,编译报错。
    在这里插入图片描述
2.遍历
//范围 for
for (auto e : s1)//e是容器元素的别名,可以随便换,但一般用e
{e++;cout << e;
}
  1. 范围for循环的核心机制:
  1. 通过容器的begin()/end()获得迭代器范围。
  2. 自动迭代(递增迭代器)。
  3. 自动解引用:自动取容器数据赋值给e。
  4. 自动判断是否结束。
  1. 跟迭代器一样,所有容器都可以用它来进行遍历,非常方便,但它底层是迭代器。

2.5 容量相关成员函数

在这里插入图片描述

  1. size():返回字符串的大小。
  2. length():返回字符串的长度。
  3. *max_size():返回字符串可以达到的最大理论长度。实际往往比理论要小,意义不大。
  4. capacity():返回已分配存储空间的大小。

vs里面,除了第一次,后续都是 1.5 倍扩容。
gcc里面,2倍扩容。

  1. clear():清空字符串里的所有字符。
  2. empty():判断是否还有字符,是否为空。是为 true,不是为 false。

7. *shrink_to_fit():

请求字符串减少其容量以适应其实际大小。

缩容代价很大,需重新分配内存:它无法直接缩小原有空间,只能去申请一块适应字符串大小的新的空间,然后将原内容拷贝到新的空间中,再释放原有空间,最后让string的内部指针指向新的空间。是一种用时间换空间的做法,一般不会这样做。

8. resize(n, c):

将字符串调整为n个字符的长度
在这里插入图片描述

  1. 如果 n 小于字符串的长度,字符串会被截断为前 n 个字符,后面的字符将被删除
  2. 如果 n 大于字符串的长度,那么会在字符串末尾插入所需数量的字符来达到 n 的大小。如果指定了 c,将会以 c 的副本作为新元素填充,未指定时,则用值初始化字符(‘\0’)进行填充。
  3. 容量够用时不会改变,不够用时会自动扩容。
string s1 = "abcdefg";
//初始值:
cout << "初始值:" << endl;
cout << "s1:" << s1 << endl;
cout << "capacity:" << s1.capacity() << endl;
cout << "size:" << s1.size() << endl;//改变大小(增)且不指定:
cout << "改变大小(增)且不指定:" << endl;
s1.resize(100);
cout << "s1:" << s1 << endl;
cout << "capacity:" << s1.capacity() << endl;
cout << "size:" << s1.size() << endl;//改变大小(减):
cout << "改变大小(减):" << endl;
s1.resize(4);
cout << "s1:" << s1 << endl;
cout << "capacity:" << s1.capacity() << endl;
cout << "size:" << s1.size() << endl;//补充:改变大小(增)且指定:
cout << "补充:改变大小(增)且指定:" << endl;
s1.resize(10, '#');
cout << "s1:" << s1 << endl;
cout << "capacity:" << s1.capacity() << endl;
cout << "size:" << s1.size() << endl;

执行结果:
在这里插入图片描述

9. reserve(n):

请求调整字符串容量,用于预先分配内存,以避免后续操作频繁分配内存,从而提高性能。扩容靠谱,缩容不靠谱
在这里插入图片描述

它会将容量调整为至少 n 个字符,但不会改变字符串的长度

  1. 若 n 大于当前容量,则必须扩容到 n 个字符或者更大的容量(考虑内存对齐等问题)。
  2. 若 n 小于等于当前容量,则不保证(非约束性)执行任何操作(容量可能保持不变,或按实现策略优化)。

2.6 元素访问相关成员函数

在这里插入图片描述

1. operator[]:

返回字符串 pos 索引处字符的引用(非 const 限定的字符串可对其进行修改)。
在这里插入图片描述

  1. 若 pos == 字符串长度,则函数会返回对空字符’\0’的引用。
  2. operator[]不进行任何边界检查,但在某些编译器如 vs 下面,一旦越界,运行时会断言报错。

2. *at(pos):

功能与 operator[] 一样,不过它在处理越界时会抛异常

在这里插入图片描述

void stirng_test06()
{string s1 = "abcdefg";s1.at(25);
}
int main()
{try{stirng_test06();}catch (const exception& e){cout << e.what() << endl;}return 0;
}

结果:
在这里插入图片描述

  1. *back():返回字符串结束位置的字符。
  2. *front():返回字符串首字符。
    在这里插入图片描述

2.7 修改相关成员函数

在这里插入图片描述
在这里插入图片描述

1. operator+=:

通过在当前字符串的末尾添加其他字符来拓展字符串。

//string
string s0 = "abcdefg";
string s1 = "###";
s0 += s1;
cout << s0 << endl;//c-string
string s2 = "abcdefg";
const char* str = "###";
s2 += str;
cout << s2 << endl;//character
string s3 = "abcdefg";
s3 += '#';
cout << s3 << endl;

结果:
在这里插入图片描述

2. *append():

追加内容,相比于operator +=,功能更加丰富,但其实平常用得不多。
在这里插入图片描述

3. *push_back():

在尾部插入一个字符。
在这里插入图片描述

4.*assign():

整体替换内容,相比于operator =,功能更加丰富,但其实平常用得不多。
在这里插入图片描述

5.*insert():

在索引为 pos 的值前插入字符或字符串。一般记住一个插入字符一个插入字符串的就行了。
在这里插入图片描述

string s1 = "abcdefg";
//字符串
s1.insert(0, "###");
cout << s1 << endl;
//字符
s1.insert(0, 1, '!');
cout << s1 << endl;
s1.insert(s1.begin(), '$');
cout << s1 << endl;

结果:
在这里插入图片描述

insert谨慎使用,涉及底层数据移动,效率低下,时间复杂度可达O(N)。

6.*erase():

删除部分字符串,减少字符串长度。
在这里插入图片描述

string s1 = "abcdefg";
//从索引为1的字符开始删,删一个
s1.erase(1, 1);
cout << s1 << endl;
//从索引为1的字符开始删,删完为止
s1.erase(1);
cout << s1 << endl;

erase:谨慎使用,涉及底层数据移动,效率低下,时间复杂度可达O(N)。

7.*replace:

用来替换字符串的一部分
在这里插入图片描述

string s1 = "abcdefg";
s1.replace(1, 3, "#");
cout << s1 << endl;

结果:
在这里插入图片描述

replace:谨慎使用,涉及底层数据移动,效率低下,时间复杂度可达O(N)。

8.swap():

整体替换,替换为 str,要注意 str 类型是 string& 而不是 const string&。
在这里插入图片描述
在之后的博客里会详细讲解。

9.pop_back():

删掉字符串最后一个字符,使长度减 1。

2.8 字符串操作相关成员函数

在这里插入图片描述

1. c_str():

返回一个指向数组的指针,该数组包含一个以’\0’结尾的字符序列,即c字符串。
在这里插入图片描述

在这里插入图片描述

  1. c_str()可以拿到底层的_str(内部指针),即指向c风格字符串的指针。
  2. 有些函数只提供c的接口(比如 fopen()等),而没有c++的接口,这种情况下,c_str()可以很好的解决这个问题。
string filename("Test.cpp");
FILE* fout = fopen(filename.c_str(), "r");
if (fout == nullptr)
{cout << "fopen fail" << endl;return;
}

2.*data():

c++11以后,功能与c_str()完全相同。

3.get_allocator():

用于获取容器当前使用的内存分配器。

在这里插入图片描述

4.*copy(s, len, pos):

拷贝当前对象的一部分到 s 所指向的数组中,从 pos(起始位置) 开始拷贝,最多拷贝 len 个字符,返回值是实际拷贝的字符数。
在这里插入图片描述

一般使用之后substr()来进行拷贝,这个用得很少。

5.substr(pos, len):

从当前字符串对象中提取子串,并通过拷贝构造返回一个新的 string 对象
在这里插入图片描述

  1. 从 pos(当前位置)开始拷贝,最多拷贝 len 个字符,若 len > 剩余字符数量,则拷贝到字符串末尾。
  2. pos 默认值是0,显式传参时不能越界,否则运行时会抛异常,len 默认值是 npos,无符号整数最大值,表示“直到字符串末尾”。

在这里插入图片描述

6.find():

查找当前字符串对象的字符或者是子字符串。
在这里插入图片描述

  1. buffer(3):s 是指向c风格字符串的指针,size_t n 中的n指的是从 s 中取前 n 个字符进行查找。
  2. 返回值:找到则返回第一次找到位置的索引;未找到则返回 npos
    在这里插入图片描述

7.*rfind():

查找当前字符串对象的字符或者是子字符串。相比于find(),用法差不多,不过它是倒着从后往前找
在这里插入图片描述

8.*find_first_of(s/c, pos):

给定一个字符串或单个字符参考集合 s 或 c,在当前字符串对象里查找第一个在参考集合里面的字符,并返回它的索引。
在这里插入图片描述

9.*find_last_of(s/c, pos):

功能和 find_first_of(s/c, pos)差不多,不过它是倒着从后往前查找。

10.*find_first_not_of(s/c, pos):

给定一个字符串或单个字符参考集合 s 或 c,在当前字符串对象里面查找第一个不在参考集合里面的字符,并返回它的索引。
在这里插入图片描述

11.*find_last_not_of(s/c, pos):

功能和 find_first_not_of(s/c, pos)差不多,不过与之相比,它是倒着从后往前查找。

12.*compare():

用来比较字符串,不过很少用到它,因为非成员函数里重载了用来比较的运算符,了解一下。

在这里插入图片描述

2.9 非成员函数

在这里插入图片描述

1.*operator+:

连接字符串并返回新的字符串,并且不会改变字符串彼此的值。
在这里插入图片描述

  1. 尽量少用,传值返回,深拷贝效率低下。
  2. 其不跟 operator+= 一同重载为成员函数的原因:

成员函数的都有一个隐藏的参数:const string& this,为了支持第一个参数为非string类型(如const char*),operator+需要被重载为非成员函数。之后的关系运算符重载函数重载为非成员函数也是这个原因。

2.relational operators:

其重载了所有的关系运算符。
在这里插入图片描述

3.swap(x, y):

交换两个字符串的值。
在这里插入图片描述

4.operator>> 与 operator<<:

让 string类对象可以像内置类型一样输入输出。

5.getline(string)

从输入流中读取一行文本(遇到’\n’停止),并将其存储到字符串对象 str 中,类似cin。使用依赖<string>头文件。
在这里插入图片描述
它与 cin 的区别:

  1. cin 读取字符串的时候,如果字符串中间有空格,它便会停止读取。cin以空白字符作为分隔符(空格、制表符、换行符)
  2. getline() 则会无视空格,一直读下去,直到遇到’\n’。默认getline以换行符’\n’作为分隔符,它也可以自己定义分隔符(delim)。
string s1;
getline(cin, s1);
cout << "s1:" << s1 << endl;
string s2;
cin >> s2;
cout << "s2:" << s2 << endl;

在这里插入图片描述


今天的分享就到此结束啦,如果对读者朋友们有所帮助的话,可否留下宝贵的三连呢~~
如果可以, 那就让我们共同努力, 一起走下去!

相关文章:

  • 驱动:字符设备驱动注册、读写实操
  • [Harmony]颜色初始化
  • [Harmony]网络状态监听
  • 5.29-6.4解决问题归纳
  • ‘pnpm‘ 不是内部或外部命令,也不是可运行的程序
  • Linux系统iptables防火墙实验拓补
  • 亚马逊站内信规则2025年重大更新:避坑指南与合规策略
  • 制造业数智化:R²AIN SUITE 如何打通提效闭环
  • 使用 useSearchParams 的一个没有触发控制台报错的错误用法
  • 某校体育场馆结构自动化监测
  • LeetCode 2297. 跳跃游戏 VIII(中等)
  • 【电赛培训课程】电子设计竞赛工程基础知识
  • Git常用命令完全指南:从入门到精通
  • 【Redis实战:缓存与消息队列的应用】
  • 30 C 语言递归算法详解:基准条件、递归逻辑、循环对比、经典案例(斐波那契、猴子吃桃、汉诺塔、二分查找等)
  • 防火墙iptables项目实战
  • golang常用库之-go-feature-flag库(特性开关(Feature Flags))
  • 关于面试找工作的总结(四)
  • Linux容器篇、第一章_02Rocky9.5 系统下 Docker 的持久化操作与 Dockerfile 指令详解
  • 电子电路:共集电极放大器原理与作用解析
  • wordpress导航文件夹/百度搜索排名优化
  • 两学一做考学网站/搜索引擎优化的概念是什么
  • 做网站买Java什么书/网络营销推广策略
  • 保定网站优化/百度搜索推广的定义
  • 福建省建设厅网站节能办/网络营销渠道
  • 青岛网站建设方案咨询/市场营销教材电子版