【C++】STL篇 string类(使用)

        string的学习会分为两个大步骤,第一步就是会使用string,第二部是模拟实现string。这篇文章我们介绍一下string类以及它的使用。string大概有一百多个接口,我们需要重点掌握的就十几二十个。string其实就是字符串,严格来说string类是一个管理字符串的类,它就是一个字符顺序表

1.标准库中的string类

下面是string类的文档介绍。

cplusplus.com/reference/string/string/?kw=stringicon-default.png?t=O83Ahttps://cplusplus.com/reference/string/string/?kw=string

使用 string 类时,必须包含 #include头文件( #include <string> )以及using namespace std ;
这里先大致说一下前面提供的文档怎么看。

顺便提一句

string其实是typedef出来的,原型是basic_string<char>,除了char类型其实还有其他的,只是不常用,了解一下即可。

2.string类的常用接口说明

2.1 string类对象的常见构造

 文档里C++98就提供了7种构造函数接口,重点有三个。

我们现在把这三种方式使用一下。

#include <iostream>
#include <string>  //头文件
using namespace std;
int main()
{
	string s1; //默认构造
	string s2("111111"); //带参构造
	string s3(s2); //拷贝构造

	return 0;
}

string是重载了流插入和流提取的,所以是可以直接用的。

string s1; //默认构造
string s2("111111"); //带参构造
string s3(s2); //拷贝构造

cout << s2 << endl;  //流提取
cout << s3 << endl;

cin >> s1; //流插入
cout << s1 << endl;

 输入中文也可以。

 2.2 其他构造函数(简单介绍)

来看(3)string (const string& str, size_t pos, size_t len = npos); 它可以算是拷贝构造(2)的一个变型,和(2)对比着来看,(2)是全部拷贝,(3)就是拷贝一部分。

从pos这个位置开始,拷贝len的长度过去。

string s4("hello world");
cout << s4 << endl;
//从下标是6的位置(w),拷贝5个字符
string s5(s4, 6, 5);
cout << s5 << endl;

 如果len比剩余字符大,不会报错,会默认拷贝到字符串结束 。

不传第三个参数,也是默认拷贝到字符串结束 。

我们可以点进这个npos看一下是什么。

 这里想表达的意思就是,字符串有多长取多长

来看(5)string (const char* s, size_t n); 它其实可以看成(4)的变形。

 取字符串s的前n个初始化。

//取hello world的前6个字符初始化
string s6("hello world", 6);
cout << s6 << endl;

来看(6)string (size_t n, char c);

取n个c字符初始化。

string s7(3, 'a');
cout << s7 << endl;

 (7)

2.3 析构函数

string类里的析构函数是自动调用的,我们不需要管。

2.4 string类对象的容量操作

 有星号的为重点。

2.4.1 size和length

size和length返回字符串有效字符长度,它们两个基本没什么区别。那为什么同样的东西有两个?这就跟C++的发展历史有关了,感兴趣的可以去了解一下,这里就不多说了。

 

//获取长度
string s8("hello world");
cout << s8.length() << endl;
cout << s8.size() << endl;

我们以后经常用到的是size

2.4.2 capacity

我们前面写的数据结构都了解过capacity的含义,所以在这里capacity也很好理解,就是容量。

 

这里我们可以了解一下vs编译器下如何扩容,看下面一段代码。

void TestPushBack()
{
	string s;
	size_t sz = s.capacity();  //保存之前容量
	cout << "capacity changed: " << sz << '\n';
	cout << "making s grow:\n";
	for (int i = 0; i < 100; ++i)
	{
		s.push_back('c');
		if (sz != s.capacity()) //capacity变化了,打印一下之前的容量大小
		{
			sz = s.capacity();
			cout << "capacity changed: " << sz << '\n';
		}
	}
}
int main()
{
	TestPushBack();
	return 0;
}

初始空间大小是15,第一次扩容,是2倍扩,从16到32,后面就是1.5倍扩。 

vs下做了特殊处理,对小于16个空间时,vs把内容存到了一个_Buf里,这个buff也并不在堆上,大于16字节之后,_Buf就废弃了,vs重新在堆上开辟一块空间存数据。所以第一次扩容是二倍扩就是因为数据从一个地方到了另一个空间,后面就都是1.5倍扩容,所以整体来看,vs下的扩容是1.5倍扩。这是vs自己的设计,不同编译器的扩容不同。了解一下即可。

2.4.3 reserve和resize

频繁的扩容其实是不好的,扩容也是一种消耗。解决方法就是用reserve和resize。常用的是reverse。

 

reserve支持我们给一个n,提前开好空间。这里的规定就是,开的空间只能大于等于n,不能少于n。vs下选择开比100大的,别的编译器可能就是刚好开100。

这里开空间是不包含'\0'的,所以实际最少最少开101字节,但是string这个capacity返回的大小都不包含'\0'的。

提前开空间可以减少扩容。

但是reserve还有可能会缩容。这取决于编译器。

 文档的意思就是:n大于或等于capacity就行,其他情况(就是小于)下capacity是否会缩小自己,是不一定的。但是capacity一定不会对string的内容和length造成影响。

 n<10和n>20是确定的,前者一定不会变,capacity不会缩的小于size,后者一定会变,变成n的大小,现在不确定的就是10<n<20的情况。

 在vs上验证一下。

string s1("aaaaaaaaaaaaaaaaaa");
cout << s1.size() << endl;
cout << s1.capacity() << endl;

 

然后reserve一个比size(18)小的数。

s1.reserve(17);
cout << s1.size() << endl;
cout << s1.capacity() << endl;

 

vs下结果不变。我们再给18到31之间的值。

 

vs下选择不缩小,不同的编译器处理方式会不同。我们再给比capacity(31)大的值。

 vs下结果是一定会扩的大于n。

2.4.4 clear和empty

clear就是把数据清除,有的编译器可能还会把容量也清除了,一般不清容量。

直接上代码演示。 

string s1("aaaaaaaaaaaaaaaaaa");
cout << s1.size() << endl;
cout << s1.capacity() << endl;

s1.clear();
cout << s1.size() << endl;
cout << s1.capacity() << endl;

 

 

empty就是判空,这没啥多说的。

2.5 string类对象的访问及遍历操作

2.5.1 operator[]

有了operator[]我们就可以访问pos位置的字符,就像我们在使用数组。同时也方便我们对其修改。

string s7(10, 'x');
cout << s7 << endl;

//访问下标为5的字符,并且修改它
s7[5] = 'b';
cout << s7 << endl;

数组的越界C++的检查是不确定的,有了operator[],如果我们越界访问,是一定会被检查出来的。

string s7(10, 'x');
cout << s7 << endl;

//越界访问
s7[11] = 'b';
cout << s7 << endl;

有了[]的重载,我们就可以配合size对这个字符串进行遍历

//下标+[]的遍历方式
string s8("hello world");
for (int i = 0; i < s8.size(); i++)
{
	cout << s8[i] << " ";
}
cout << endl;

2.5.2 迭代器 begin+end

除了上面这种下标+[]的遍历方式,string还支持迭代器的方式进行遍历。迭代器是我们前面提到过的STL六大组件其中一个,可以用来遍历和访问容器。先看下面代码,后面会解释。

//迭代器遍历
string s8("hello world");
string::iterator it = s8.begin();
while (it != s8.end())
{
	cout << *it << " ";
	++it;
}
cout << endl;

 现在来对这几行代码进行一个解释。

 

迭代器提供了一种通用的访问方式,所有的容器都可以用iterator访问,所有容器都有自己的iterator。begin和end在文档的iterators这个位置。

 

 更详细的介绍自己去文档里看一下,这里就不细说了。

2.5.3 auto和范围for

C++11里面提供的遍历方式,叫范围for,所有容器也都可以用它遍历。先看代码。

//范围for
string s8("hello world");
for (auto ch : s8)
{
	cout << ch << " ";
}
cout << endl;

现在来解释一下这个范围for和auto。

范围for自动从s8这个容器获取每一个字符,给ch这个变量,ch变量的类型是auto,auto的意思就是自动推导,自动推导ch的类型。当然把auto换成char也可以。 

只要类型匹配就行,auto就是自动匹配类型。范围for自动赋值,自动迭代,自动判断结束,它的底层就是迭代器。

这里要注意,范围for改变不影响容器的值。

string s8("hello world");
string::iterator it = s8.begin();
while (it != s8.end())
{
	*it += 2;  //把所有字符加2
	cout << *it << " ";
	it++;
}
cout << endl;

for (char ch : s8)
{
	ch -= 2; //还原所有字符
	cout << ch << " ";
}
cout << endl;
cout << s8 << endl; //s8还原了吗??

我们一顿操作之后发现,s8在迭代器里改变了,范围for里并没有被还原。

前面说过,范围for底层就是迭代器,范围for部分的代码从迭代器角度理解就相当于我们把*it给给了ch,而ch只是string里面每个字符的拷贝,相当于ch只是一个局部变量,我们只是修改了这个局部变量,并没有修改string里面对应的字符。迭代器为什么可以修改?迭代器可以想象成是一个像指针的东西,*it就是string里的一个字符,直接修改。

如果范围for想修改s8,我们可以引用传参。如下。

for (auto& ch : s8)  //引用传参,参数类型自动推导
{
	ch -= 2; //还原所有字符
	cout << ch << " ";
}

前面提到的三种遍历方式没特别大的区别,按需使用。

范围for遍历数组是非常方便的,如下。

	for (auto a : arr) //不做修改 
		cout << a << " ";
    //要修改就引用传参

在这里补充2C++11的小语法,方便我们后面的学习。

·在早期 C/C++ auto 的含义是:使用 auto 修饰的变量,是具有自动存储器的局部变量,后来这个 不重要了。 C++11 中,标准委员会变废为宝赋予了 auto 全新的含义即: auto 不再是一个存储类型 指示符,而是作为一个新的类型指示符来指示编译器, auto 声明的变量必须由编译器在编译时期 推导而得
·用 auto 声明指针类型时,用 auto auto* 没有任何区别,但用 auto 声明引用类型时则必须   加  &。
·当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译   器实际 只对第一个类型进行推导,然后用推导出来的类型定义其他变量
·auto 不能作为函数的参数,可以做返回值,但是建议谨慎使用。
·auto 不能直接用来声明数组。

2.5.4 反向迭代器rbegin

前面说到的迭代器是正向迭代器,string里还有反向迭代器rbegin。

先看一下反向迭代器的使用效果。 

//反向迭代器
string::reverse_iterator rit = s8.rbegin();
while (rit != s8.rend())
{
	cout << *rit << " ";
	rit++; //这里还是++不是--
}
cout << endl;

来解释一下反向迭代器。 只是简单像下面这样理解。

这里的rit已经不是原生指针了,指针++绝对不会是倒着加。现在我们只需要知道、会用反向迭代器就行。

还有一种情况就是const修饰的string。仔细看迭代器其实给了两种情况,拿begin举例。

 普通对象返回普通迭代器,const对象返回const迭代器。const迭代器的特点就是只能读不能写

const string s9("hello world");
string::const_iterator cit = s9.begin();
while (cit != s9.end())
{
	cout << *cit << " ";//只读
	++cit; //自己可以改,s9不可以改
}

总结:

迭代器有4种:

iterator   (正向迭代器,最常见)      

const_iterator  ( const正向迭代器)

reverse_iterator  (反向迭代器)

const_reverse_iterator  (const反向迭代器)

本次分享就到这里,拜拜~

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

STM32传感器模块编程实践(八) HX711压力传感器称重模块简介及驱动源码

文章目录 一.概要二.HX711主要技术指标三.HX711模块参考原理图四.模块接线说明五.模块工作原理介绍六.模块通讯协议介绍七.STM32单片机与HX711模块实现重量测量实验1.硬件准备2.软件工程3.软件主要代码4.实验效果 八.小结 一.概要 电子秤是将检测与转换技术、计算机技术、信息…

一文通透OpenAI o1:从CoT、Quiet-STaR、Self-Correct、Self-play RL、MCST等技术细节到工程复现

前言 注意&#xff0c;本文自10.12日起&#xff0c;正在每天更新的过程中&#xff0c;包括已写的部分也在不断修改(以增加更多技术细节、更加通俗易懂) 预计10.20完成第一版&#xff0c;10月底修订到第二版——具体修订记录详见本文文末.. 可能是去年写或讲的关于ChatGPT原理的…

植物大战僵尸杂交版之后要出联机版植物大战僵尸?(内测中,可在安卓手机上玩,文末附下载链接)

继植物大战僵尸杂交版之后给大家介绍一个杂交版作者正在酝酿的“植物大战僵尸射击版” 植物大战僵尸射击版介绍 《植物大战僵尸杂交版》的创作者“潜艇伟伟迷”即将推出PVZ改版新作——《植物大战僵尸射击版》。游戏将支持PC、手游和web端&#xff0c;提供单人、双人、三人、…

【java Web如何开发?】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

华为eNSP实验:交换机流量控制之风暴控制

一、交换机流量控制之风暴控制 风暴控制是交换机流量控制中的一种重要机制&#xff0c;用于防止网络中的广播、多播或单播风暴对网络性能造成破坏。具体如下&#xff1a; 基本原理&#xff1a;风暴控制通过监控端口的入站流量&#xff0c;并与预设的风暴抑制级别进行对比来管…

java数组讲解

前言&#xff1a; 由上两章&#xff0c;我们已经了解关于java的基础语法&#xff0c;这章我们将讲解数组的相关语法&#xff0c;坐好了没&#xff0c;我们准备要发车啦&#xff01;&#xff01;&#xff01; 我们将从五部分给大家讲解&#xff1a; 1数组的基本概念 2.数组是…

使用Windows创建一个MFC应用【带界面】

MFC使用教程【对初学者保姆型友好&#xff01;】 目录 前提条件 1&#xff1a;创建MFC应用程序 2. 项目结构解读 引用 外部依赖项 头文件 源文件 资源文件 文件功能详解 项目的主要流程 步骤2&#xff1a;配置OpenCV 安装OpenCV 包含目录与库文件 步骤3&#xff1…

Milvus×Dify半小时轻松构建RAG系统

最近&#xff0c;检索增强生成&#xff08;RAG&#xff09;技术在AI界引起了广泛关注。作为一种将知识库与生成模型结合的新型架构&#xff0c;RAG大大提升了AI应用的实际表现。而在构建RAG系统时&#xff0c;Milvus作为业界领先的开源向量数据库&#xff0c;扮演着关键角色。本…

视频格式在线转换,五种超实用的视频格式转换工具!

视频内容无处不在&#xff0c;从教育课程到娱乐电影&#xff0c;从社交媒体分享到在线会议&#xff0c;视频已成为我们日常生活中不可或缺的一部分。然而&#xff0c;不同的设备和平台支持的视频格式各异&#xff0c;会导致视频文件在某些设备上无法播放。因此&#xff0c;掌握…

计算机毕业设计python+spark知识图谱课程推荐系统 课程预测系统 课程大数据 课程数据分析 课程大屏 mooc慕课推荐系统 大数据毕业设计

指导教师意见&#xff1a; 1&#xff0e;对“文献综述”的评语&#xff1a; 对教育领域数据可视化的相关背景和现状做了综述&#xff0c;明确了课题的研究目标和研究重点&#xff0c;并对研究手段进行了概述。为后面的毕业设计做好了准备。 对本课题的深度、广度及工作量的…

【开源】第三期:数字货币程序化交易终端开源

关于初衷&#xff1a; 这篇文章&#xff0c;其实应该在六年前发出来&#xff0c;但是受制于各种杂事和生活琐事&#xff0c;一直拖到现在&#xff0c;想必有朋友看到在"终端"那期里&#xff0c;聊到的数字货币交易的实践&#xff0c;那个时候遍地都是数字货币交易所&…

git gui基本使用

一、图形化界面 二、创建新项目 创建文件&#xff0c;加入暂存区&#xff0c;提交到版本库 三、创建分支 四、合并分支 1.切换至master 五、更新分支 六、解决冲突 修改冲突&#xff0c;加入暂存区&#xff0c;提交到版本库 七、远程创建库 Gitee - 基于 Git 的代码托管和研…

储能硬件实物图

B 薄膜电容 薄膜电容 D 杜邦线 杜邦线 G 固态电容 固态电容 I IGBT iGBT S 散热片 散热片 Y 压敏电阻 压敏电阻 液冷板 液冷板

瑞萨IDE:CS+ for CC编译过程中执行脚本文件

最近发现使用CS for CC IDE发现一个很有意思的功能。编译工程过程中&#xff0c;IDE自动执行Python脚本和批处理脚本&#xff0c;极大地提高开发效率。 编写好脚本文件后&#xff0c;在IDE中选择CC-RH&#xff08;Build Tool&#xff09;->Common Options->Others。 Co…

SQL进阶技巧:如何找出开会时间有重叠的会议室?| 时间区间重叠问题

目录 0 场景描述 1 数据准备 2 问题分析 方法1&#xff1a;利用 lateral view posexplode()函数将表展开成时间明细表 方法2&#xff1a;利用数学区间讨论思想求解 3 小结 如果觉得本文对你有帮助&#xff0c;想进一步学习SQL语言这门艺术的&#xff0c;那么不妨也可以选…

arm架构ceph pacific部署

背景 合作伙伴实验室的华为私有云原来使用单点的nfs做为存储设备&#xff0c;现有两方面考量&#xff0c;业务需要使用oss了&#xff0c;k8s集群及其他机器也需要一套可扩展的分布式文件系统 部署ceph 初始机器配置规划 IP配置主机名Role10.17.3.144c8g1T数据盘ceph-node01…

Apache Seatunnel Zeta引擎-启动脚本分析

Apache SeaTunnel Zeta引擎的集群模式启动的第一步是执行bin/seatunnel-cluster.sh脚本&#xff0c;所以先来学习下这个脚本。 脚本执行流程分析 脚本简要注释 #!/bin/bash # # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license a…

Java项目:154 基于ssm旅游信息网站(含论文+ppt)

作者主页&#xff1a;源码空间codegym 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 使用旅游信息网站的分为管理员和用户两个角色的权限子模块。 管理员所能使用的功能主要有&#xff1a;个人中心、用户管理、旅游景点管理、交…

双指齐下:那晚我与算法的不解之缘

公主请阅 1.快乐数1.1题目说明示例 1示例 2 1.3题目分析1.4代码部分1.5代码解析 2.复写02.1题目说明示例 1示例 2 2.2题目分析2.3代码部分2.4代码解析 1.快乐数 题目传送门 1.1题目说明 编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」定义为&#xff1a; 对于一个正…

探索 Blob 对象的应用场景和实例分析

一. 引言 当我们在开发 Web 应用程序时&#xff0c;常常会遇到需要处理二进制数据的情况。这时&#xff0c;Blob&#xff08;Binary Large Object&#xff09;对象就成为了一个非常有用的工具。Blob 对象可以用来表示一段二进制数据&#xff0c;它可以存储和操作各种类型的数据…