初识C++ · string的使用(1)

news2024/11/25 12:46:09

目录

1 STL简介

2 string类

2.1 构造 析构 拷贝

2.2 size length

2.3 [ ]的使用

2.4 迭代器

2.5 Push_Back和append

3 sort的使用


1 STL简介

STL是一个标准库,是C++标准库的一个重要部分,那么什么是STL?STL是一个模板库,包含了算法框架和数据结构

STL有不同的版本,比如原始版本,P.J 版本,R.W 版本,SGI版本,不同版本有不同的特点,比如SGI版本的可移植性好,比如P.J版本的可读性较差。

STL这个库里面有六大部分,分别是算法,容器,迭代器,仿函数,空间配置器,配接器。我们即将介绍的,是容器部分的string,可以形象的把容器理解为数据结构,里面还有链表list,树set,顺序表vector等。

这里简单说明,就进入string的正式部分了。


2 string类

string首先是一个类,是委员会发明类之前的一个“前车”,所以成员函数部分可能有点冗余,比如函数有120多个。

string类是字符数组,可以进行增删查改,但是这里的字符不一定是一个字节,通过后面的学习就知道了,比如w_char就是4字节,我们先不做了解。

2.1 构造 析构 拷贝

constructor就是构造的意思,所以这里面进入,就是构造函数的真面目了:

构造函数就有7个,这也是造成冗余的原因之一.

int main()
{
	string s;
	return 0;
}

 第一个构造函数使用如上,即什么也不干,那么s里面就是空的,什么也没有,也可以通过调试观察里面有什么,当然,里面有其他的,我们先不做深究。

int main()
{
	string s1("abcdefg");
	cout << s1 << endl;
	return 0;
}

第二个构造使用如上,很简单,但是为什么支持直接打印呢?因为流重载重载了string类,所以可以打印,那么这也是个验证的好方法。const string& str就是常量字符串的意思,所以我们给上常量字符串就行了。

int main()
{
	string s1("abcdefg");
	string s4(s1);
	return 0;
}

第四个构造使用如上,也就是给一个字符串的指针就可以了,使用很常见,也很实用。

以上3个构造函数的最常用到的,后面三个可以作为了解,毕竟有点鸡肋的。

int main()
{
	string s1("abcdefg");
	string s2(s1, 0, 3);
	cout << s1 << endl;
	cout << s2 << endl;
	return 0;
}

这个构造重载的参数有3个,分别是常量字符串,pos,npos,我们看文档的时候不如连蒙带猜,平时的pos使用是位置的意思,比如之前链表,顺序表的时候pos是位置的索引,即从常量字符串的pos位置开始,那么什么时候结束呢?

到npos位置的时候结束:

查看文档发现,npos的值是-1?但是是size_t类型的,并且下面写到Maximum value for size_t,结合之前介绍的char的轮盘,可以知道npos是42亿多。

那么函数的意思就是从pos位置拷贝一直到npos?什么字符串要占4个G的大小?

所以结合文档(string太短了或者len的值是npos,就会直接拷贝完)

int main()
{
	string s1("abcdefg");
	string s2(s1, 0);
	string s3(s1, 0,30);
	return 0;
}

第一个我们只给了两个参数,那么函数就使用缺省值,即npos,第二个给了三个,但是30明显超出了s1的大小,所以这俩个字符串都是拷贝完s1,实际上使用的时候不会有第二种的写法。

int main()
{
	string s5("Hello world",5);
    cout << s5 << endl;
	return 0;
}

第五个函数的意思就是从一个常量字符串里面拷贝多少个字节进去,我们从Hello World里面拷贝5个字节进去,那么打印出来就是Hello。

int main()
{
	string s7(10, 'x');
    cout << s7 << endl;
	return 0;
}

第六个函数的意思就是拷贝n个c字符到string里面去。

以上3个作为了解,实际用处不太大的。

第7个涉及到了迭代器,暂时不介绍。

destructor即析构函数,析构没什么特殊的,出了作用域,string就自己销毁了,不需要自己去销毁。

拷贝有个很舒服的地方在于可以直接使用=:

当然,重载也重载了三个拷贝函数,

int main()
{
	string s1 = "abcdefg";
	string s2 = s1;
	cout << s1 << endl;
	cout << s2 << endl;
	return 0;
}

使用起来也是很方便,底层是怎么操作的我们就不用深究了,但是肯定是发生了隐式类型准换的,s1想要引用,就加const即可。

第三个函数就不用深究了,作用不大。


2.2 size length

在C语言中,我们计算数组的大小常常是size/size,在string中,我们直接调用size就行了:

int main()
{
	string s1 = "abdeef";
	cout << s1.size() << endl;
	cout << s1.length() << endl;
	return 0;
}

但是通过文档,我们发现size和length没有区别,都是返回string的长度,那么出现两个相同功能的函数的原因是因为string发明太早了,我们对于一个字符串可以说大小也可以说长度,顺序表也是,但是对于后面的树等结构,长度不太说的过去,所以对于string来说,length最初是专门为它服务的,大小是都能用的,length只有string可以用,所以最好后面统一使用size。


2.3 [ ]的使用

以前访问数组我们通常使用下标 + [ ]进行访问,这点在string里面都是可以使用的,但是这里实际上和数组访问有区别,这里不是指针偏移,这是调用的函数,[]重载。

int main()
{
	string s1 = "abcdefg";
	for (int i = 0; i < s1.size(); i++)
	{
		cout << s1[i];
	}
	return 0;
}

可是如果到这里你觉得[]就介绍完了你就大错特错辣。

class string
{
public:
	char& operator[](size_t pos)
	{
		assert(pos < _size);
		return _str[pos];
	}

private:
	char* _str;
	size_t _size;
	size_t _capacity;
};

string里面的[]重载函数如上,第一个重点是引用返回,因为是引用返回,所以可以减少拷贝,第二个重点是,assert,因为使用了暴力检查,所以越界了就会直接报错:

既然是引用返回,所以我们可以修改字符串里面的内容,但是[]重载有两个版本,一个是普通版本没有const,一个是const版本,当我们不希望string被修改的时候就可以:

int main()
{
	const string s2("123456");
	s2[1] = 'a';
	return 0;
}


2.4 迭代器

迭代器iterator,有如上几个函数,实际上我们了解前4个就可以了,后面以c开头的其实就是const,表示迭代的元素不能被修改而已。

先看使用:


int main()
{
	string s1("Hello world");
	string::iterator it1 = s1.begin();
	while (it1 != s1.end())
	{
		cout << *it1 << " ";
		it1++;
	}
	return 0;
}

因为iterator是公有函数,所以使用的时候必须加上类名+类域访问符,使it1 = s1.begin(),就是相当于it1从字符H开始,end同理,end就是字符串的最后一个标志->'\0',那么这里看起来十分像指针,但是并不是,不如我们来看看类型。

int main()
{
	cout << typeid(string::iterator).name() << endl;
	return 0;
}

吓人吧?但是目前来说我们可以把它当作指针使用,但是我们只发挥了它的一层功力。

我们现在讨论一个问题,遍历一个字符数组有多少种方式?

遍历方式1:下标 + []

int main()
{
	string s1("Hello world");
	for (int i = 0; i < s1.size(); i++)
	{
		cout << s1[i];
	}
	return 0;
}

遍历方式2:迭代器

int main()
{
	string s1("Hello world");
	string::iterator it1 = s1.begin();
	while (it1 != s1.end())
	{
		cout << *it1 << " ";
		it1++;
	}
	return 0;
}

遍历方式3:范围for

int main()
{
	string s1("Hello world");
	for (auto e : s1)
	{
		cout << e;
	}
	return 0;
}

第一种方式没有什么好说的,第二种是迭代,第三种实际上底层也是调用的迭代器,来看看:

已经出现了刚才那个一长串的类型了,就不用多说了吧?

所以范围for循环底层也是通过迭代器实现的。

当我们进入到begin的文档就会大仙有两个版本,const和普通版本:

int main()
{
	const string s1("Hello world");
	string::const_iterator it1 = s1.begin();
	while (it1 != s1.end())
	{
		cout << *it1;
		it1++;
	}
	return 0;
}

const的作用不用多说,这里要注意的是为什么const_iterator,而不是const iterator?

我们类比指针,如果是const int* p ,那么修饰的是*p,指向不能变,如果是int* const p,就是修饰的p本身,那么如果是const iterator,修饰的就是迭代器本身,本身不能改变,还谈何遍历呢?

所以C++采用的方式是const_iterator。

接着就是rbegin的使用,如果说begin是正方向遍历,rbegin就是逆方向遍历,r也不难猜出来,Reverse,逆置。

使用如下:

int main()
{
	string s1("Hello world");
	string::reverse_iterator it1 = s1.rbegin();
	while (it1 != s1.rend())
	{
		cout << *it1;
		it1++;
	}
	return 0;
}

加个reverse_,同const一样的,使用了之后begin都要变成rbegin。

可能有疑问了,这里++?为什么不是--,实际上++是重载之后的--,不难想象++就是倒着回去遍历的。

2.5 Push_Back和append及+=

数据离不开插入数据:

Push_back即尾插,在字符串末尾插入一个数据,插入之后,对应的字符串长度也会增加。

int main()
{
	string s1("Hello world");
	s1.push_back('x');
	cout << s1 << endl;
	return 0;
}

push_back是插入一个字符,append是插入一个字符串,append插入的字符串可以是一个字符吗?那也是可以的,一个字符也可以是字符串:

int main()
{
	string s1("Hello world");
	s1.append("x");
	s1.append("abcd");
	cout << s1 << endl;
	return 0;
}

当然,这里也是有许多重载的,我们也是可以连蒙带猜的去猜使用方法的,但是实际上使用最多的是第三个,后面的其实,用处不太大;

int main()
{
	string s1("Hello world");
	string s2("123456");
	s1.append(s2,4,5);
	s1.append(s2,4);
	cout << s1 << endl;
	return 0;
}

这里就不介绍了看看文档咯。

当然类似的,有插入就有删除,比如尾删pop_back等,就不介绍了:

但是呢,还是略显麻烦了,不就是加个字符吗?string有个堪称神力的重载:

 不管是push_back还是append在这个重载面前都黯然失色了,因为这个太方便:

int main()
{
	string s("aaa");
	s += "bbb";
	s += "c";
	cout << s << endl;
	return 0;
}

要加什么直接加上去就行了,很方便。 


3 sort的使用

讲了这么多string内部的函数,这里就介绍一点实际应用,string是一种容器(数据结构),那么容器是存储数据的,算法是修改数据的,他们之间的联系靠迭代器完成,为什么说迭代器不是冗余的设计,因为迭代器是两者之间的桥梁,使用如下:

int main()
{
	string s1("Hello world");
	sort(s1.begin(), s1.end());
	cout << s1 << endl;
	return 0;
}

这里按照字典序排列,即ASCII码值排列字符串,sort所在的头文件是algorithm,中文意思就是算法的意思,sort的使用要注意左闭右开

左闭右开有个优点就是好计算总共排序多少元素,因为左减右就直接算出来了,这里是对整个string进行排序,如果想要进行部分排序,只需要:

int main()
{
	string s1("Hello world");
	sort(s1.begin(), s1.end() + 5);
	cout << s1 << endl;
	return 0;
}

这里是对前5个元素进行排序,可以看到离不开迭代器。


感谢阅读!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python自动化测试 | 如何使用Robot Framework进行自动化测试?

你还在手动测试&#xff1f;不妨了解一下更高效、准确且简单的测试方法——使用Python的Robot Framework进行自动化测试。 什么是Robot Framework&#xff1f; Robot Framework是一款开源的Python自动化测试框架&#xff0c;它基于关键字驱动的思想&#xff0c;具有易读、易扩…

Day_4

1. 地址簿功能 查询地址列表 属于常规方案 新增地址 属于常规方案 修改地址 删除地址 设置默认地址 2. 用户下单业务 数据库分析 订单表和订单明细表的关系&#xff1a;一对多 代码开发 controller 层 service 层 异常处理&#xff08;收货地址为空、超出配送范围、购物…

使用规则进行命名实体识别(NER)

使用规则进行命名实体识别&#xff08;NER&#xff09; 命名实体识别&#xff08;Named Entity Recognition&#xff0c;NER&#xff09;是自然语言处理&#xff08;NLP&#xff09;中的一项基础任务&#xff0c;它旨在从文本中识别出具有特定意义的实体&#xff0c;如人名、地…

【Unity从零开始学习制作手机游戏】第01节:控制3D胶囊体运动

1. 新建Project L01 使用3D Mobile模板。 2. 建立一个平面&#xff0c;用来承载物体 3. 导入Unity库内的胶囊体 下载 StandardAssets https://download.unitychina.cn/download_unity/e80cc3114ac1/WindowsStandardAssetsInstaller/UnityStandardAssetsSetup-5.6.7f1.exe …

STM32真的是很落后吗?

STM32 真的是很落后吗&#xff1f;这是一个值得探讨的问题。 STM32 是意法半导体&#xff08;STMicroelectronics&#xff09;推出的一款 32 位微控制器&#xff0c;它在嵌入式领域有着广泛的应用。虽然我对 Python 的了解有限&#xff0c;无法直接对 STM32 进行深入的比较&am…

系统定时器(SysTick)

介绍SysTick SysTick结构框图 时钟选择 计数器部分 中断部分 工作流程 相关寄存器 配置流程 相关库函数

【Nginx】如何在 Nginx 中阻止来自特定国家的 IP 地址访问

文章目录 前言一、准备工作二、查看 Nginx 服务器都拥有哪些模块2.1 先查看本地nginx是否有ngx_http_geoip2模块2.2 安装nginx并配置ngx_http_geoip2模块2.2.1下载所需版本的nginx到服务器2.2.2 先安装所需依赖2.2.3 解压文件2.2.4 下载ngx_http_geoip2模块2.2.5 编译安装nginx…

linux笔记5--shell命令2

文章目录 一. linux中的任务管理1. 图形界面2. 命令① top命令② grep命令③ ps命令补充&#xff1a; ④ kill命令图形界面杀死进程 二. 挂载(硬盘方面最重要的一个知识点)1. 什么是挂载2. 关于挂载目录① Windows② linux查看硬件分区情况(/dev下)&#xff1a;更改挂载目录结束…

gitignore配置不生效记录

第一种可能性&#xff1a; 在你所有的文件都通过了git add . 命令的情况下&#xff0c;使用指令git rm -r --cached .进行缓存清除&#xff0c;完成之后&#xff0c;再次通过git add . 然后通过git status去看提交的文件都有哪些。 第二种可能性 如果上面的不行就是你添加的…

如何开展性能测试工作

性能测试是确保软件系统在预期负载下能够稳定、高效运行的重要环节。它帮助识别和优化系统的瓶颈&#xff0c;确保应用在真实环境中的表现满足用户需求。 一 性能测试的需求来源 为什么要做性能测试&#xff0c;预测的性能风险是什么 压测目标涉及的接口及业务场景描述 压测…

纯血鸿蒙APP第三方库——MpChart运动健康场景实践案例

介绍 MpChart是一个包含各种类型图表的图表库&#xff0c;主要用于业务数据汇总&#xff0c;例如销售数据走势图&#xff0c;股价走势图等场景中使用&#xff0c;方便开发者快速实现图表UI&#xff0c;MpChart主要包括线形图、柱状图、饼状图、蜡烛图、气泡图、雷达图、瀑布图…

粒子群算法(Particle Swarm Optimization)

注意&#xff1a;本文引用自专业人工智能社区Venus AI 更多AI知识请参考原站 &#xff08;[www.aideeplearning.cn]&#xff09; 算法背景 粒子群优化算法&#xff08;Particle Swarm Optimization&#xff0c;PSO&#xff09;的灵感来源于鸟群或鱼群的觅食行为。想象一下&a…

QX---mini51单片机学习---(9)中断系统

目录 1什么是中断 2中断系统在单片机系统中的作用 3如何使用单片机的中断系统 4实践 1什么是中断 RST P0想输出高电平接上拉电阻 2中断系统在单片机系统中的作用 3如何使用单片机的中断系统 可位寻址&#xff1a;IE中的EA可以直接&#xff0c;EA1&#xff1b; 外部中断&…

OSS证书自动续签,一分钟轻松搞定,解决阿里云SSL免费证书每3个月失效问题

文章目录 一、&#x1f525;httpsok-v1.11.0支持OSS证书自动部署介绍支持特点 二、废话不多说上教程&#xff1a;1、场景2、实战Stage 1&#xff1a;ssh登录阿里云 ECSStage 2&#xff1a;进入nginx &#xff08;docker&#xff09;容器Stage 3&#xff1a;执行如下指令Stage 3…

第五百零三回

文章目录 1. 概念介绍2. 使用方法2.1 普通路由2.2 命名路由 3. 示例代码4. 内容总结 我们在上一章回中介绍了"使用get显示Dialog"相关的内容&#xff0c;本章回中将介绍使用get进行路由管理.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在本章…

【算法】滑动窗口——最小覆盖子串

本节博客是对“最小覆盖子串”题目由暴力求解到滑动窗口的思路解析&#xff0c;有需要借鉴即可。 目录 1.题目2.滑动窗口解法3.总结 1.题目 题目链接&#xff1a;LINK 这个题目是困难难度&#xff0c;感觉是一个中等题目的感觉。 首先我肯定想到的是暴力求解的方法&#xff…

Spring:@Async注解使用注意事项及九大失效场景

前言 原文作者&#xff1a;微信公众号&#xff1a;苏三说技术 场景举例 代码案例 点击此处可观看&#xff1a;Async注解使用注意事项及九大失效场景

7B2 PRO主题5.4.2 免授权开心版源码 | WordPress主题

简介&#xff1a; B2 PRO 5.4.2 最新免授权版不再需要改hosts&#xff0c;和正版一样上传安装就可以激活。 直接在WordPress上传安装即可 点击下载

DS:顺序表、单链表的相关OJ题训练(2)

欢迎各位来到 Harper.Lee 的学习世界&#xff01; 博主主页传送门&#xff1a;Harper.Lee的博客主页 想要一起进步的uu欢迎来后台找我哦&#xff01; 一、力扣--141. 环形链表 题目描述&#xff1a;给你一个链表的头节点 head &#xff0c;判断链表中是否有环。如果链表中有某个…

Spring框架概述

目录 1. Spring框架的起源 2. Spring框架的构成 3. Spring的发展历程 4. Spring的开发环境 4.1. Maven安装与配置 &#xff08;1&#xff09;Maven的下载与安装 &#xff08;2&#xff09;配置Maven的环境变量 &#xff08;3&#xff09;本地仓库的配置 &#xff08;4…