【C++】STL简介 | string类的常用接口

目录

STL简介

学string类前的铺垫

概念

为什么要学string类

string类的底层(了解)

编码表的故事

string类的常用接口与应用

3个必掌握的构造

赋值

访问字符operator[]

初识迭代器(iterator)

反向迭代器

用范围for遍历

string类对象的修改操作

插字符push_back()

插字符串append()

超好用的operator+=

指定位置插字符insert()

string类对象的容量操作

只开空间的reserve()

开空间+初始化的resize()


STL简介

什么是STL?

全称为Standard Template Library(标准模板库),是C++标准库的重要组成部分。

它不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架。

通俗来说,STL就是将常见的数据结构(如顺序表,链表,栈,队列,二叉树,哈希等)以模板的形式进行封装,使用时,不用人为再

去写,可以直接调用。并且,一些常见的通用的算法也不用自己实现,可以直接从STL调用。

六大组件:

这个目前了解即可,后面会具体学到。

 

STL的众多组件中,我们从容器里的string类学起。

学string类前的铺垫

概念

String类是用于处理字符串的类。String类提供了一系列的方法,用于处理字符串,包括连接字符串、查找子字符串、获取字符串长度等。

为什么要学string类

处理字符串的方法,我们之前在C语言中也学到过。如字符串函数strlen、strcpy、strcat……,对于字符串的处理主要是求长度、追加、查找等,这些就是string要代替那些字符串函数完成的操作。

那已经有了字符串函数,为什么还要搞一个string类出来呢?

这时因为,字符串函数与字符串是分离开的,不太符合面向对象编程 的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。

所以说,我们需要更好用的string类。

string类的底层(了解)

实际上,编C++的大佬并没有直接写一个string类,而是写了一个basic_string模板类。

string类在底层上实际是:basic_string 模板类的别名。

typedef basic_string<char, char_traits, allocator>string;

string就是basic_string<char>。是basic_string的char类型 的实例化。

❓问题来了:为什么不直接实现sring类,而是写一个模板呢?

这与编码表有关,我们接着往下看。

编码表的故事

计算机最开始是从美国发源的。美国人的交流是建立在ABCD的字母组合上,而计算机只认得01串。

为了在计算机上交流,美国人发明了一套ASKII编码,统一规定了字母和常用符号用哪些二进制数来表示。

 

这样一来,如果我们写进了一个'A',那计算机中实际存储的是用01表示出的65:

int main()
{char a = 'A';return 0;
}

如果我们要存储"happy"这个单词的话,那计算机中实际存储的分别是h、a、p、p、y对应的ASKII码值。

如果存数字1234,那会开4个char字节,依次存入1、2、3、4的ASKII值:

补充:所以说,string类的123+string类的1,不等于124!而是1231:

但ASKII编码表并不是万能的。对于美国等来说,字母加上常用字符有一百来个,一个字节八个比特位(最多表示256位)完全够用了。

但对于文化博大精深的中国来说,汉字、繁体字的数量庞大,一个字节根本不够表示,这要怎么办呢?

中国科学家齐心协力,自定了一套编码表,名叫GB2312。这时用两个字节,16个比特位,来表示常用的汉字。后来,经过不断更新,又出台了GBK标准,能表示更多的汉字。

这里补充一点:在中国的编码表中,读音相同的字是编在一起的。所以,净网行动下,跟国粹读音相同的词都会被屏蔽。如果你发“卧槽”,结果是“* *”,如果改发“握草” “沃槽”,结果还是“ * *”。

但是问题又来了:不同国家的人用不同的编码标准,一个美国人给一个中国人发文件,因为编码表译出来的不同,打开就是乱码了,这要怎么办?

 

为了解决这个问题,科学家发明了Unicode(万国码)。它包含了世界上所有的符号,所有语言都可以互通,一个网页上也可以显示多国语言。

但问题又来了:像中国这样文字多的国家,要用两个字节去表示字符,那对于原本一个字节就够用的语言,现在也要跟着用两个字节。这对计算机空间会造成极大的浪费。

对此的解决方案是:UTF-8!

“UTF-8(8位元,Universal Character Set/Unicode Transformation Format)是针对Unicode的一种可变长度字符编码。它可以用来表示Unicode标准中的任何字符,而且其编码中的第一个字节仍与ASCII相容,使得原来处理ASCII字符的软件无须或只进行少部分修改后,便可继续使用。因此,它逐渐成为电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。”

(源自:百度百科)

所以说,这些字符不一定只占一个字节,也可能占两个字节甚至更多。因此,不能简单地实现string,需要一个模板,即basic_string。

“basic_string是一个模板类,它是C++标准库中用于处理字符串的通用工具类。它提供了一种灵活且可扩展的方式来处理字符串,允许使用不同的字符类型(例如char、wchar_t(宽字节)等)和分配策略。"

string类的常用接口与应用

3个必掌握的构造

下面三个标”重点“的, 要掌握

注:用string类要包头文件#include<string>

函数名称功能说明
string() (重点)构造空的string类对象,即空字符串
string(const char* s) (重点)用C-string来构造string类对象
string(size_t n, char c)string类对象中包含n个字符c
string(const string& s) (重点)拷贝构造函数

演示:

#include<iostream>
#include<string>     
using namespace std;
int main()
{string s1;  //构造空的string类对象
​string s2("hello");  //用C-string来构造string类对象
​string s3(s2);   //拷贝构造
​cout << s1 << endl;cout << s2 << endl;cout << s3 << endl;return 0;
}

其他构造就不一一演示了,最重要的是得学会看文档。通过文档,我们能快速上手它的用法。

下面演示,通过看文档,掌握substring:

 

用起来:

#include<iostream>
#include<string>
using namespace std;
int main()
{string s1("hello");  string s2(s1, 0, 2);  //从s1的第0位开始,往后拷贝2位cout << s1 << endl;cout << s2 << endl;return 0;
}

赋值

有三种赋值方式:

#include<iostream>
#include<string>
using namespace std;
int main()
{string s1("hello"),s2; s2 = s1;         //Way 1cout << s2 << endl;
​s2 = "happy";    //Way 2cout << s2 << endl;
​s2 = 'h';       //Way 3cout << s2 << endl;
​return 0;
}

访问字符operator[]

string实现了operator[],可以访问字符串的字符。

1.修改

因为返回的是引用,所以我们可以对返回的该字符进行修改。这使字符串用起来就像数组一样:

#include<iostream>
#include<string>
using namespace std;
int main()
{string s1("hello"); cout << s1[1] << endl;
​s1[1] = 'p';cout << s1 << endl;return 0;
}

2.遍历

也可以遍历数组,配合size()使用:

 

#include<iostream>
#include<string>
using namespace std;
int main()
{string s1("hello"); for (int i = 0; i < s1.size(); i++) {cout << s1[i] << "  ";}return 0;
}

补充说明一点:其实有个跟size()功能差不多的函数:length(),也能求字符串长度。

但是更推荐用size(),因为它更通用。许多容器里不能用length(),但可以用size()。

3.检查越界

operator[]内部会检查越界,一旦越界就会报错。

示例:

#include<iostream>
#include<string>
using namespace std;
int main()
{string s1("hello"); cout << s1[10] << endl;  //越界return 0;
}

4.(了解) 功能相同的at()

at()的功能跟operator()相同,也是访问字符。

 

at()是像函数一样去调用:

#include<iostream>
#include<string>
using namespace std;
int main()
{string s1("hello"); for (int i = 0; i < s1.size(); i++) {cout << s1.at(i) << "  ";      //注意调用方式}return 0;
}

那at()和operator()的区别是什么呢?

两者检查越界的方式不一样。opreator()是断言,激进一点的处理方式,断言会把程序直接终止掉。at()是抛异常,比较温和的处理方式。一般用try catrch来捕获异常,程序还能继续跑。

初识迭代器(iterator)

迭代器是STL框架设计的六大组件之一,非常重要。现阶段先对迭代器做一个大致的了解。

什么是迭代器 (iterator)?

"迭代器是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址。

迭代器修改了常规指针的接口,迭代器是一种概念上的抽象,那些行为上像迭代器的东西都可以叫做迭代器。迭代器有很多不同的能力,它可以把抽象容器和通用算法有机的统一起来。"

(源自百度百科)

现阶段我们对迭代器的理解是:像指针一样的类型,有可能就是指针,也可能不是指针,但用法像指针一样。(内部细节得后面我们自己实现了才知道)

那我们就先认为它是指针。

迭代器都是在类的内部定义的,属于这个类域。

如果要用的话,记得标明类域:

string::iterator

一个类里面有四种迭代器:

iterator
const_iteratorreverse_iterator
const_reverse_iterator

接下来,每种迭代器都用来遍历一下。

➡️用迭代器iterator去遍历:

#include<iostream>
#include<string>
using namespace std;
int main()
{string s1("hello"); string::iterator it = s1.begin();while (it != s1.end()) {     //Q:这里用<可以吗?   A:于string可以,但是其他容器可能就不行了。!=是通用的写法cout << *it << " ";   //用法像指针it++;}return 0;
}

 

begin获取一个字符的迭代器 ,end获取最后一个字符后一个位置的迭代器:

➡️用const_iterator去遍历:

#include<iostream>
#include<string>
using namespace std;void PrintString(const string& s) {string::const_iterator it = s.begin();  //形参被const修饰,此时不能再用iterator,不然是权限的放大while (it != s.end()) {cout << *it << " ";it++;}cout << endl;
}
int main()
{string s1("hello"); PrintString(s1);return 0;
}

补充:

其实string不太用迭代器,因为operator[]更好用。

那用迭代器遍历的意义是什么呢?

因为iterator是所有容器通用的访问方式,并且用法类似。某些容器如map/list/set……只能用迭代器访问。

反向迭代器

(先了解一下,后面会手把手实现反向迭代器)

反向迭代器,顾名思义,可以实现反向遍历数组。

reverse_iterator   //反向迭代器

➡️使用reverse_iterator遍历:

#include<iostream>
#include<string>
using namespace std;
int main()
{string s1("hello"); string::reverse_iterator rit = s1.rbegin();   //使用反向迭代器while (rit != s1.rend()) {cout << *rit << " ";rit++;}cout << endl;return 0;
}

 

右闭 (区间) 左开 (区间) :

➡️使用const_reverse_iterator遍历:

#include<iostream>
#include<string>
using namespace std;
​
void PrintString(const string& s) {string::const_reverse_iterator it = s.rbegin();   //注意得用const_reverse_iteratorwhile (it != s.rend()) {cout << *it << " ";it++;}cout << endl;
}
int main()
{string s1("hello"); PrintString(s1);return 0;
}

用范围for遍历

遍历字符串,除了上面讲到的两种方法,还可以用范围for去遍历:

#include<iostream>
#include<string>
using namespace std;
int main()
{string s1("hello"); for (auto e : s1) {    //把s1的每个字符取出来,依次赋给ecout << e << " ";}cout << endl;return 0;
}

 

范围for遍历的好处在于:既能自动迭代,又能自动判断结束。

不过,范围for在底层实现上没啥技术含量,其实就是迭代器。

string类对象的修改操作

插字符push_back()

 

示例:

#include<iostream>
#include<string>
using namespace std;
int main()
{string s1("hello ");s1.push_back('u');    //只能插入一个字符,不能插字符串!cout << s1 << endl;return 0;
}

插字符串append()

这里用得最多的是(1)和(3):

 

示例:

#include<iostream>
#include<string>
using namespace std;
int main()
{string s1("hello ");s1.append("world");   //只能插字符串,不能插字符cout << s1 << endl;return 0;
}

超好用的operator+=

刚刚那两位,在operator+=面前,就相形见绌了。operator+=不仅能加字符、字符串,甚至还能加对象!

示例:

#include<iostream>
#include<string>
using namespace std;
int main()
{string s1("hello ");  s1 += "world";   //插字符串s1 += '!';       //插字符
​string s2("see u soon");s1 += s2;         //插对象cout << s1 << endl;return 0;
}

指定位置插字符insert()

要掌握(1)、(3)、(6):

练习:

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台(字符串相加)

string类对象的容量操作

只开空间的reserve()

注意:是reserve(保留)不是reverse(逆置)。

void reserve (size_t n = 0);

当n大于当前字符串容量时,会扩容至n;

当小于,则容量不变。

此函数对字符串长度没有影响,也不能更改其内容。

注意看capacity的变化:

开空间+初始化的resize()

相比reserve的之开空间,resize既能开空间,同时还能初始化。

void resize (size_t n);     //⑴不指定初始化的值,那默认初始化为
void resize (size_t n, char c);    //⑵指定初始化为c

示例⑴:

示例⑵:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/135633.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【微信小程序】swiper的使用

1.swiper的基本使用 <jxz-header></jxz-header> <view class"banner"><swiperprevious-margin"30rpx"autoplayinterval"2000"indicator-dotsindicator-color"rgba(0,0,0,0.3)"indicator-active-color"#bda…

每日一题 337. 打家劫舍 III

难度&#xff1a;中等 整体思路相当于是前两天的方法倒过来&#xff0c;毕竟二叉树最常用的解法就是递归倒推 对于每一颗子树&#xff0c;他必定有一种最大的盗取方法&#xff0c;但是只有它的 root 的盗取情况才会影响到 root 的父节点&#xff0c;即如果收益最大的盗取方法…

虚拟线上发布会带来颠覆性新体验,3D虚拟场景直播迸发品牌新动能

虚拟线上发布会是近年来在数字化营销领域备受关注的形式&#xff0c;而随着虚拟现实技术的不断进步&#xff0c;3D虚拟场景直播更成为了品牌宣传、推广的新选择。可以说&#xff0c;虚拟线上发布会正在以其颠覆性的新体验&#xff0c;为品牌带来全新的活力。 1.突破时空限制&am…

竞赛选题 基于深度学习的人脸性别年龄识别 - 图像识别 opencv

文章目录 0 前言1 课题描述2 实现效果3 算法实现原理3.1 数据集3.2 深度学习识别算法3.3 特征提取主干网络3.4 总体实现流程 4 具体实现4.1 预训练数据格式4.2 部分实现代码 5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 毕业设计…

09MyBatisX插件

MyBatisX插件 在真正开发过程中对于一些复杂的SQL和多表联查就需要我们自己去编写代码和SQL语句,这个时候可以使用MyBatisX插件帮助我们简化开发 安装MyBatisX插件: File -> Settings -> Plugins -> 搜索MyBatisx插件搜索安装然后重启IDEA 跳转文件功能 由于一个项…

计算机竞赛 深度学习 opencv python 公式识别(图像识别 机器视觉)

文章目录 0 前言1 课题说明2 效果展示3 具体实现4 关键代码实现5 算法综合效果6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于深度学习的数学公式识别算法实现 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学…

Unity Bolt 实现UI拖拽功能

最近在学习使用Bolt插件实现五代码对UGUI Image元素实现拖拽。先看效果 录制_2023_09_15_17_50_45_29 下面是实现方式介绍&#xff1a; 1&#xff1a;注册RectTransformUtility 在使用Bolt插件实现UI拖拽的功能&#xff0c;需要使用 RectTransformUtility.ScreenPointToLoca…

操作系统基本概念

目录 一、基本概述 二、操作系统的特点 &#xff08;一&#xff09;并发性&#xff08;实质是微观的串行、宏观的并行&#xff09; 1. 对比看&#xff1a;并行性 2. 单核CPU和多核CPU &#xff08;二&#xff09;共享性 &#xff08;三&#xff09;虚拟性 &#xff08;…

自动化和数字化在 ERP 系统中意味着什么?

毋庸置疑&#xff0c;ERP系统的作用是让工作更轻松。它可以集成流程&#xff0c;提供关键分析&#xff0c;确保你的企业高效运营。这些信息可以提高你的运营效率&#xff0c;并将有限的人力资本重新部署到更有效、更重要的需求上。事实上&#xff0c;自动化和数字化是ERP系统最…

【Unity程序技巧】Unity中的单例模式的运用

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;Uni…

爬虫 — 验证码反爬

目录 一、超级鹰二、图片验证模拟登录1、页面分析1.1、模拟用户正常登录流程1.2、识别图片里面的文字 2、代码实现 三、滑块模拟登录1、页面分析2、代码实现&#xff08;通过对比像素获取缺口位置&#xff09; 四、openCV1、简介2、代码3、案例 五、selenium 反爬六、百度智能云…

【QT】day2

1.完善登录框 点击登录按钮后&#xff0c;判断账号&#xff08;admin&#xff09;和密码&#xff08;123456&#xff09;是否一致&#xff0c;如果匹配失败&#xff0c;则弹出错误对话框&#xff0c;文本内容“账号密码不匹配&#xff0c;是否重新登录”&#xff0c;给定两个按…

分布式缓冲-Redis

个人名片&#xff1a; 博主&#xff1a;酒徒ᝰ. 个人简介&#xff1a;沉醉在酒中&#xff0c;借着一股酒劲&#xff0c;去拼搏一个未来。 本篇励志&#xff1a;三人行&#xff0c;必有我师焉。 本项目基于B站黑马程序员Java《SpringCloud微服务技术栈》&#xff0c;SpringCloud…

神经网络 02(激活函数)

一、激活函数 在神经元中引入了激活函数&#xff0c;它的本质是向神经网络中引入非线性因素的&#xff0c;通过激活函数&#xff0c;神经网络就可以拟合各种曲线。 如果不用激活函数&#xff0c;每一层输出都是上层输入的线性函数&#xff0c;无论神经网络有多少层&#xff0c…

(vue2)面经基础版-案例效果分析

配路由 先配一级&#xff0c;一级里面配二级。一级路由&#xff1a;首页&#xff08;二级&#xff1a;嵌套4个小页面&#xff09;、详情页 高亮a->router-link&#xff0c;高亮效果对自带高亮类名router-link(-exact)-active设置 注&#xff1a;通过children配置项&#…

使用vite创建vue3项目及项目的配置 | 环境准备 ESLint配置 prettier配置 husky配置

使用vite创建vue3项目及项目的配置 1.环境准备 使用vite搭建项目&#xff0c;vite需要nodejs版本14.18、16 node v18.16.1pnpm 8.7.4 pnpm:performant npm(高性能的npm)由npm/yarn衍生而来&#xff0c;解决了npm/yarn内部潜在的bug&#xff0c;极大的优化了性能&#xff0c…

能用就行——玄学问题:Compile with TORCH_USE_CUDA_DSA to enable device-side assertions

配置&#xff1a; python 3.9.0&#xff0c;torch2.0.1cu118 背景&#xff1a; 一直使用这个配置训练都没问题。搁置了一个月之后&#xff0c;再次使用就显示报错“Compile with TORCH_USE_CUDA_DSA to enable device-side assertions.” 过程&#xff1a; 尝试了网上的各种方…

【SG滤波】三阶滤波、五阶滤波、七阶滤波(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

气传导耳机对耳朵有伤害吗?气传导耳机哪款好?

​随着气传导耳机的快速发展&#xff0c;在运动、办公等场合能够经常看到&#xff0c;带来了前所未有的舒适体验。作为一种新型耳机类型&#xff0c;相较传统入耳式耳机来说&#xff0c;更有利于耳道卫生&#xff0c;在听歌时还能保持对环境声的感知。面对市面上这么多气传导耳…

GEE:快速实现NDVI时间序列NDVI线性趋势和变化敏感性计算(斜率、截距)

作者:CSDN @ _养乐多_ 本博客将向您介绍如何使用Google Earth Engine(GEE)平台来处理Landsat 5、7和8的卫星图像数据,计算NDVI的斜率和截距,以及如何导出这些结果供进一步分析使用。 文章目录 一、代码详解1.1 核心代码详解1.2 核心代码详解1.3 代码框架介绍二、完整代码…