[C++] STL简介及string常用接口说明

目录

STL简介

标准库中的string类

string类的常用接口说明

1. string::string

2. string::operator[]

3.iterator

4. 反向迭代器

5.std::sort

6. append 与 push_back 与 operator+=

7.insert 与 erase

8.replace

9.size 与 capacity 与 max_size

11.resize

12.find查找 substr提取字符

13.operator+

14.stoi 与 to_string

15.at与operator[ ]

总结


STL简介

STL(Standard TemplateLibrary),即标准模板库,从根本上说,STL是一些“容器”的集合,这些“容器”有list、vector、set、map等,STL也是算法和其他一些组件的集合。STL的目的是标准化组件,这样就不用重新开发,可以使用现成的组件。

STL包含了诸多在计算机科学领域里常用的基本数据结构和基本算法。为广大C++程序员们提供了一个可扩展的应用框架,高度体现了软件的可复用性。从逻辑层次来看,在STL中体现了泛型化程序设计的思想(generic programming)。在这种思想里,大部分基本算法被抽象,被泛化,独立于与之对应的数据结构,用于以相同或相近的方式处理各种不同情形。

STL六大组件

  1. 容器(Containers):各种数据结构,如VectorDequeListSetMap,用来存放数据,STL容器是一种Class Template,就体积而言,这一部分很像冰山载海面的比率。
  2. 算法(Algorithms):各种常用算法,如SortSearchCopyErase,从实现的角度来看,STL算法是一种Function Templates。
  3. 迭代器(Iterators):扮演容器与算法之间的胶合剂,是所谓的“泛型指针”,共有五种类型,以及其它衍生变化,从实现的角度来看,迭代器是一种将:Operators*Operator->Operator++Operator–等相关操作予以重载的Class Template。所有STL容器都附带有自己专属的迭代器,只有容器设计者才知道如何遍历自己的元素,原生指针(Native pointer)也是一种迭代器。
  4. 仿函数(Functors): 即函数对象,行为类似函数,可作为算法的某种策略(Policy),从实现的角度来看,仿函数是一种重载了Operator()的Class 或 Class Template。一般函数指针可视为狭义的仿函数
  5. 配接器(适配器)(Adapters):一种用来修饰容器(Containers)或仿函数(Functors)或迭代器(Iterators)接口的东西,例如:STL提供的QueueStack,虽然看似容器,其实只能算是一种容器配接器,因为它们的底部完全借助Deque,所有操作有底层的Deque供应。改变Functor接口者,称为Function Adapter;改变Container接口者,称为Container Adapter;改变Iterator接口者,称为Iterator Adapter。配接器的实现技术很难一言蔽之,必须逐一分析。
  6. 分配器(Allocators):即空间配置器,负责空间配置与管理,从实现的角度来看,配置器是一个实现了动态空间配置、空间管理、空间释放的Class Template。

标准库中的string类

  1. string是表示字符串的字符串类

  2. 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。

  3. string在底层实际是:basic_string模板类的别名,typedef basic_string<char, char_traits, allocator> string;

  4. 不能操作多字节或者变长字符的序列。

在使用string类时,必须包含#include头文件以及using namespace std

string类的常用接口说明

1. string::string

 int main()
 {
     //常用
     string s1;               //空串
     string s2("hello world");//将hello world字符串拷贝到s2
     string s3(s2);           //将s2拷贝到s3
     string s4(s2, 2, 5);     //将s2从下标为2的字符开始拷贝5个字符到s4
     string s5("hello", 3);   //将hello字符串的前3个字符拷贝到s5
     string s6(5, 'd');       //连续拷贝5个d到s6
     cout << s1 << endl; 
     cout << s2 << endl;
     cout << s3 << endl;
     cout << s4 << endl;
     cout << s5 << endl;
     cout << s6 << endl;
     return 0;
 }

也可以直接用流插入和流提取

     string s7;
     cin >> s7;
     cout << s7 << endl;

2. string::operator[]

返回字符串中对位置pos处字符的引用

  1. 越界可以检查出来

  2. 非const类型 可以对字符串进行修改

  3. const与非const同时存在时,编译器会自动调用最合适的

size和length的功能相同,主要是为与STL相同使用,以后都用size

遍历方式1:下标访问

 //遍历字符串
 void test3() {
     string s1("hello world");
     cout << s1.size() << endl;//11
     cout << s1.length() << endl;//11 同size相同功能
     //遍历方式1:下标
     for (size_t i = 0; i < s1.size(); i++) {
         //cout << s1.operator[](i) << " ";
         cout << s1[i] << " ";
         cout << s1[i+1] << " ";//修改
     }
     s1[2] = 'c';
     s1[30];//越界能检查出来
     cout << endl;
 }
     const string s2("hello world");
     //不能修改
     s2[3] = 'c';//error

3.iterator

begin:任何容器返回第一个数据位置的iterator

end:任何容器返回最后一个数据位置的iterator

遍历方式2:迭代器

 void test4() {
     //遍历方式2:iterator
     //迭代器 iterator--通用方式
     string s1("hello world");
     string::iterator it1 = s1.begin();
     while (it1 != s1.end()) {
         cout << *it1 << " ";
         ++it1;
     }
     cout << endl;
     cout << typeid(it1).name()<< endl;//得到it1 的类型-理解为类似指针的东西
 }

遍历方式3:范围for

     //遍历方式3:范围for-所有容器支持
     for (auto e : s1) {
         //自动取值给e,自动++,自动判断结束
         cout << e << " ";
     }
 //底层就是迭代器
     cout<<endl;

const_iterator与const iterator的区别

 void test4() {
     const string s1("hello world");
     //string::const_iterator it1 = s1.begin();
     auto it1 = s1.begin();//自动识别类型
     while (it1 != s1.end()) {
         //不能修改
         //*it1 += 2;//error
 ​
         cout << *it1 << " ";
         ++it1;
     }
 }

4. 反向迭代器

rbegin 与 rend

 void test5() {
     const string s1("hello world");
     //string::const_reverse_iterator it1 = s1.rbegin();
     auto it1 = s1.rbegin();
     while (it1 != s1.rend()) {
         //不能修改
         //*it1 += 2;//error
         cout << *it1 << " ";
         ++it1;
     }
 }

5.std::sort

包含在<algorithm>头文件中

Sorts the elements in the range [first,last) into ascending order.

左闭右开

#include<algorithm>
​​​​​​​void test6(){
     string s1("hello world");
     cout << s1 << endl;
     //按字典序排序 
     //sort(s1.begin(), s1.end());
     //从第2个到倒数第2个排序
     //sort(s1.begin() + 1, s1.end() - 1);
     //排前5个字母——[0,5)
     sort(s1.begin() , s1.begin() + 5 );
 ​
     cout << s1 << endl;
 }

6. append 与 push_back 与 operator+=

三个都是尾插

 void test7()
 {
     string s1("hello world");
     cout << s1 << endl;
 ​
     string s2(s1);
     cout << s2 << endl;
 ​
     string s3(s1);
     cout << s3 << endl;
 ​
     s3.append(s1);//尾插s1
     cout << s3 << endl;
 ​
     s2.append(s1, 0, 5);//尾插s1中的前5个字符
     cout << s2 << endl;
 ​
     s1.append("hhh", 2);//尾插hhh中的前2个字符
     cout << s1 << endl;
 ​
     s1.append("lll");//尾插lll
     cout << s1 << endl;
 ​
     s1.append( 2,'j');//尾插2个j
     cout << s1 << endl;
     //push_back
     s1.push_back('2');//尾插一个字符
     cout << s1 << endl;
 }

但是尾插接口还是operator+=是最好用的

//operator+=
s1 += "1111";
s1 += s2;
cout << s1 << endl;

7.insert 与 erase

intsert 和 erase 慎用,效率低下,每个字符都要挪动

 void test8() {
 ​
     string s1("hello world");
     cout << s1 << endl;
     string s2(s1);
     s1.assign("111");//替代了s1
     s1.insert(0,"222");//在下标是0 的位置 插一个字符串
     s1.insert(0, 1, '0');//插入一个字符
     s1.insert(s1.begin(), 'y');//插入一个字符
     s1.insert(s1.begin(), s2.begin(), s2.end());//在s1的begin插入 从s2的begin到s2的end
     //下标要合法,长度可以不合法
     s1.erase(0, 1);//头删一个字符
     s1.erase(100);//不传参数/传参数很大-直接删完
      
     cout << s1 << endl;
 }

8.replace

同样效率低,需要挪动每个字符

 void test9()
 {
     string s1("hello world");
     s1.replace(0, 1, "jj");//把第一个字符替换成jj
     cout << s1 << endl;
 }

练习:把所有空格替换成%20

 //低效率
 string s2("hello world hello bit");
 for (size_t i = 0; i < s2.size();) {
     if (s2[i] == ' ') {
         s2.replace(i, 1, "%20");
         i += 3;
     }
     else {
         i++;
     }
 }
 cout << s2 << endl;

要想提高效率,就牺牲空间

 string s3(s2);
 string s4;
 //将数据放在新字符串中,提高效率
 for (auto ch : s3) {
     if (ch != ' ') {
         s4 += ch;
     }
     else {
         s4 += "%20";
     }
 }

相关的练习:

917. 仅仅反转字母 - 力扣(LeetCode)

 class Solution {
 public:
     bool isLetter(char ch){
     if(ch >= 'A' && ch <= 'Z'){
         return true;
     }
     if(ch >= 'a' && ch <= 'z'){
         return true;
     }
     return false;
 }
     string reverseOnlyLetters(string s){
         if(s.empty()){
             return s;
         }
         int  begin = 0,end = s.size() - 1;
         while(begin < end){
             while(begin < end && !isLetter(s[begin])){
                 ++begin;
             }
             while(begin < end && !isLetter(s[end])){
                 --end;
             }
             swap(s[begin],s[end]);
             ++begin;
             --end;
         }
         return s;
     }
 ​
 };

387. 字符串中的第一个唯一字符 - 力扣(LeetCode)

 class Solution {
 public:
 //计数排序
     int firstUniqChar(string s) {
         int count[26] = {0};
         for(auto ch : s){
             count[ch - 'a']++;
         }
         for(size_t i = 0; i <s.size(); i++){
             if(count[s[i] - 'a'] == 1){
                 return i;
             }
         }
         return -1;
     }
 };

125. 验证回文串 - 力扣(LeetCode)

 class Solution {
 public:
     bool isLetterOrNumber(char ch){
         return (ch >= '0' && ch <= '9')
             ||(ch >= 'a' && ch <= 'z')
             ||(ch >= 'A' && ch <= 'Z');
     }
     bool isPalindrome(string s) {
         for(auto& ch: s){
             if(ch >= 'A' && ch <= 'Z')
                 ch += 32;
         }
         int begin = 0,end = s.size() - 1;
         while(begin < end){
             while(begin < end && !isLetterOrNumber(s[begin])){
                 ++begin;
             }
             while(begin < end && !isLetterOrNumber(s[end])){
                 --end;
             }
             if(s[begin] != s[end]){
                 return false;
             }
             else{
                 ++begin;
                 --end;
             }
         }
         return true;
     }
 };

415. 字符串相加 - 力扣(LeetCode)

 class Solution {
 public:
     string addStrings(string num1, string num2) {
         int end1 = num1.size() - 1;
         int end2 = num2.size() - 1;
         int next = 0;
         string str;
         while(end1 >= 0 || end2 >= 0){
             int x1 = end1 >= 0 ? num1[end1--] - '0': 0;
             int x2 = end2 >= 0 ? num2[end2--] - '0': 0;
             int x = x1 + x2 + next;
             //处理进位问题
             next = x / 10;
             x = x % 10;
             // //头插
             // str.insert(str.begin(), '0'+x);
             //尾插
             str +=('0' + x);
         }
         // if(next == 1){
         //     str.insert(str.begin(), '1');
         // }
         if(next == 1){
             str += '1';
         }
         reverse(str.begin(), str.end());
 ​
         return str;
     }
 };

9.size 与 capacity 与 max_size

size与length功能相同,size是通用的,所以尽量使用size

capacity 在vs2022中开辟的空间小于16时,编译器会在buff[  ]存储,当扩容时,会在栈上重新开启空间,释放寄存器的空间,主要是为了提高效率,减少内存碎片。

max_size不常用,可得到的最大内存数,了解即可。

 void test1() {
     string s1("hello world");
     cout << s1.size() << endl;
     cout << s1.length() << endl;
     cout << s1.capacity() << endl;
     cout << s1.max_size() << endl;
 }

10.reserve

扩容—VS2022中本身存在buff[ ]上,第一次扩容属于在堆上开空间,第二次扩1.5倍 具体如何扩容,C++没有明确的规定,具体看编译器

reserve可以扩容,但是用于缩容是不可取的,因为不同编译器下结果不同。

void test2() {
 ​
     //reserve扩容 但不一定缩容
     string s1("1111111");
     cout << s1.size() << endl;
     cout << s1.capacity() << endl;
     s1.reserve(100);
     cout << s1.size() << endl;
     cout << s1.capacity() << endl;
     cout << endl;
     //缩容
     s1.reserve(10);
     cout << s1.size() << endl;
     cout << s1.capacity() << endl;
     cout << endl;
 }

11.resize

将字符串大小调整为 n 个字符的长度。

如果 n 小于当前字符串长度,则当前值将缩短为其第一个 n 个字符,从而删除第 n个字符之外的字符。

如果 n 大于当前字符串长度,则通过在末尾插入所需数量的字符来扩展当前内容,以达到 n 的大小。如果指定了 c,则新元素将初始化为 c 的副本,否则,它们是值初始化的字符(空字符)。

删除的空间是不能单独释放的

 //resize
 void test3() {
     string s1;
     s1.resize(5,'0');
     s1[4] = '4';
     s1[3] = '3';
     s1[2] = '2';
     s1[1] = '1';
     s1[0] = '0';
     cout << s1 << endl;
     //resize扩容
     string s2("2222222222222222222222222222");
     cout << s2.size() << endl;
     cout << s2.capacity() << endl;
     s2.resize(100);
     cout << s2.size() << endl;
     cout << s2.capacity() << endl;
     //插入(空间不足就扩容)
     string s3("hello world");
     s3.resize(20, 'x');
     cout << s3 << endl;
     //删除
     s3.resize(5);
     cout << s3 << endl;
 }

12.find查找 substr提取字符

find正序查找,rfing逆序查找

 //find查找 substr提取字符
 void test4() {
     //查找到最后一个.及后所有内容
     string file("string.cpp.zip");
     size_t pos = file.rfind('.');
     string suffix = file.substr(pos);
     cout << suffix << endl;
 ​
     string url("https://legacy.cplusplus.com/reference/string/string/?kw=string");
     //查找并提取网站的协议
     size_t pos1 = url.find(':');
     string url1 = url.substr(0, pos1 - 0);
     cout << url1 << endl;
     //查找并提取网站的网址
     //从pos1后3个字符的位置开始找
     size_t pos2 = url.find('/', pos1 + 3);
     string url2 = url.substr(pos1 + 3, pos2 - (pos1 + 3));
     cout << url2 << endl;
     //查找并提取网站后面的内容
     string url3 = url.substr(pos2 + 1);
     cout << url3 << endl;
 ​}

练习字符串最后一个单词的长度牛客题霸牛客网 (nowcoder.com)

     void test6() {
         string s;
         //默认规定空格或者换行时多个值的分割,不能提取有空格的内容
         //cin >> s;
         //getline 遇到空格才截止包含在<string>头文件中
         getline(cin, s);
         size_t pos = s.rfind(' ');
         cout << s.size() - (pos + 1) << endl;
 }

getline用于输入带有空格的内容,遇到空格不会截止,也可以自定义遇到其他符号才能截止

还有一种输入空格不截止的方法:

 //输入多行字符,连续打印
 void test7()
 {
     string str;
     while (cin >> str) {
         cout << str << endl;
     }
     //Ctrl+c杀进程
     //ctrl+z结束进程
 }

13.operator+

operator+的功能是 字符串加string类型,string加字符串,string加string。

void test5() {
 ​
     string s1("hello");
     string s2("world");
     string ret1 = s1 + s2;
     cout << ret1 << endl;
 ​
     string ret2 = s1 + " " + "hhhh";
     cout << ret2 << endl;
 ​
     string ret3 = "kkkk" + s1;
     cout << ret3 << endl;
     //operator< 按ASCII值比较
     cout << (s1 < s2) << endl;
 }
​

14.stoi 与 to_string

stoi将string类型转换成int类型

to_string将整形或浮点型转换为string类型

注意:太长的字符串是不能转成整型的,因为整型有范围,存不下,容易崩溃。

 //stoi  to_string
 void test8()
 {
     //to_string 整形转成字符串
     int x = 0, y = 0;
     cin >> x >> y;
     string str = to_string(x + y);
     cout << str << endl;
     //stoi stoll   字符串转成整型——很长的字符串转不了整型
     int z = stoi(str);
     cout << z << endl;
 }

15.at与operator[ ]

越界提示

operator[ ]会出现警示弹窗

at则会出现提示语“invalid string position”

 void test9{
     string s2("11111111111111");
     try {
         //at_访问pos位置的字符
         //s2[10];//暴力
         s2.at(10);
     }
     catch (const exception& e) {
         cout << e.what() << endl;
     }
 }
 //invalid string position

总结

string的接口是了解C++接口的开始,以上每个接口都应熟练掌握,其他只需了解即可,要常是阅读英语文档,了解本意,有时候翻译会不准确会造成误差。熟练掌握这些接口后,使用其他接口时就会轻松很多。​​​​​​​

  • 29
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值