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

目录

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个元素进行排序,可以看到离不开迭代器。


感谢阅读!

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

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

相关文章

Sass终极指南:从基础到高级,打造高效、可维护的CSS代码!

在现代网页开发中&#xff0c;CSS预处理器已经成为提高样式表维护性和可扩展性的重要工具。Sass&#xff08;Syntactically Awesome Style Sheets&#xff09;是其中最受欢迎的预处理器之一。本文将全面详细地介绍Sass&#xff0c;包括其基本介绍、主要作用、使用方法及注意事项…

2024年NOC大赛创客智慧(西瓜创客)Python复赛编程真题模拟试卷包含答案

NOC复赛python模拟题 1.编写一个程序&#xff0c;提示用户输人一个矩形的长度和宽度&#xff0c;并输出其面积, 2.试计算在区间 1 到 n的所有整数中,数字x(0≤x≤9)共出现了多少次?例如在 1到11 中&#xff0c;即在 1,2,3.45,6.7,8.9,10,11 中&#xff0c;数字 1出现了 4 次.…

工程师工具箱系列(3)Arthas

文章目录 工程师工具箱系列&#xff08;3&#xff09;Arthas安装与准备Arthas插件使用场景查看某个变量值ognl方式调用Bean方法tt(TimeTunel)方式调用Bean的方法ognl调用带参数方法 资源总览 工程师工具箱系列&#xff08;3&#xff09;Arthas Java诊断利器 安装与准备 window…

大厂常见算法50题-两数相加

专栏持续更新50道算法题&#xff0c;都是大厂高频算法题&#xff0c;建议关注, 一起巧‘背’算法! 文章目录 题目解法总结 题目 解法 定义一个节点pre&#xff0c;用于初始化结果链表的头部&#xff0c;cur指向pre&#xff0c;它将在遍历过程中用于构建新的链表。初始化进位变…

微服务部署不迷茫:4大部署模式深度解析,轻松驾驭云原生时代

微服务部署最全详解(4种常见部署模式) 微服务多实例部署 每个微服务都独立部署在自己的运行环境中&#xff0c;这是微服务架构的核心思想。 一般会采用每个主机多个服务实例&#xff0c;如下所示&#xff1a; 这是一种传统的应用部署方法&#xff0c;每个服务实例在一个或多个…

腐烂的橘子BFS

题目&#xff1a; 腐烂的橘子 在给定的 m x n 网格 grid 中&#xff0c;每个单元格可以有以下三个值之一&#xff1a; 值 0 代表空单元格&#xff1b; 值 1 代表新鲜橘子&#xff1b; 值 2 代表腐烂的橘子。 每分钟&#xff0c;腐烂的橘子 周围 4 个方向上相邻 的新鲜橘子…

FMEA再什么情况下应用——SunFMEA软件

FMEA作为一种系统性的方法&#xff0c;旨在识别和评估潜在的故障模式、其可能的影响以及相应的预防措施&#xff0c;因此&#xff0c;它的适用场景广泛且多样。今天SunFMEA软件系统和大家一起探讨什么情况下应用FMEA&#xff1f; 首先&#xff0c;在产品设计阶段&#xff0c;F…

对比分析汽车灯罩材料使用聚碳酸酯(PC)和PMMA(亚克力)的优缺点,汽车车灯的灯罩如果破损破裂破洞了要怎么修复?

对比分析汽车灯罩材料使用聚碳酸酯&#xff08;PC&#xff09;和PMMA&#xff08;亚克力&#xff09;的优缺点&#xff0c;并给出建议。 要求&#xff1a; 1. 对比分析两种材料的性能、成本、耐用性、安全性等方面的差异。 2. 给出针对不同应用场景&#xff08;如夜间照明…

通过GRE隧道实现OSPF、BGP、IS-IS的套接使用

正文共&#xff1a;999 字 9 图&#xff0c;预估阅读时间&#xff1a;1 分钟 书接上文&#xff08;专线入云场景能否配置动态路由协议&#xff1f;&#xff09;&#xff0c;我们发现通过一定的配置&#xff0c;具体就是组合使用IBGP和静态路由&#xff0c;在使用云专线接入到资…

应用层(上篇)

应用层 应用层协议原理 网络应用程序体系解构 应用程序体系结构: 由应用程序研发者设计规定了如何在各种端系统上组织该应用程序。在选择应用程序体系结构时&#xff0c;应用程序研发者很可能利用现代网络应用程序中所使用的两种主流体系结构之一:客户-服务器体系结构或对等…

快解析Tplink端口映射如何设置

Tplink作为国内知名路由器品牌&#xff0c;有着广泛的用户群体。使用快解析端口映射是实现内网服务器被外网访问必须要做的设置&#xff0c;很多对网络不懂得小白不知道该到哪里去做&#xff0c;下面我就讲解一下tplink路由器如何做端口映射。 1&#xff1a;访问路由器 &#…

Co-Driver:基于 VLM 的自动驾驶助手,具有类人行为并能理解复杂的道路场景

24年5月来自俄罗斯莫斯科研究机构的论文“Co-driver: VLM-based Autonomous Driving Assistant with Human-like Behavior and Understanding for Complex Road Scenes”。 关于基于大语言模型的自动驾驶解决方案的最新研究&#xff0c;显示了规划和控制领域的前景。 然而&…

通过钉钉卡片进行工单审批

我们通常通过钉钉机器人来发送通知&#xff0c;提醒审批人名下有待办工单需要处理。这种通知方式仅能提醒审批人到ITSM中处理&#xff0c;审批人需要打开电脑登陆平台处理&#xff0c;我们就考虑是否能有一种方式能够满足移动端审批&#xff1f; 这里我们可以使用ITSM的移动端版…

使用Flask部署Web应用:从入门到精通

文章目录 第一部分&#xff1a;准备工作第二部分&#xff1a;部署Flask应用到AWS部署到AWS Lambda 第三部分&#xff1a;部署Flask应用到腾讯云服务器部署到腾讯云服务器 第四部分&#xff1a;优化和扩展结论 在现代软件开发中&#xff0c;Web应用的部署是一个至关重要的环节。…

前端铺子-uniapp移动端:跨平台开发新篇章

一、引言 在移动应用开发领域&#xff0c;随着技术的不断进步&#xff0c;用户对应用的需求也日益多样化。如何快速、高效地开发跨平台应用成为了前端开发者面临的一大挑战。uni-app作为一款使用Vue.js开发所有前端应用的框架&#xff0c;凭借其一次编写、多端运行的特性&…

LaTeX 2024软件安装教程(附软件下载地址)

软件简介&#xff1a; 软件【下载地址】获取方式见文末。注&#xff1a;推荐使用&#xff0c;更贴合此安装方法&#xff01; LaTeX 2024是一款基于ΤΕΧ技术的专业排版系统&#xff0c;特别适用于制作科技和数学文档&#xff0c;输出高品质印刷效果。它不仅能处理学术报告、…

一篇文章拿下Redis 通用命令

文章目录 Redis数据结构介绍Redis 通用命令命令演示KEYSDELEXISTSEXPIRE RedisTemplate 中的通用命令 本篇文章介绍 Redis 的通用命令, 通用命令在 Redis 的所有数据类型下都使用, 学好通用命令可以让我们更好的使用 Redis. Redis数据结构介绍 Redis 是一个key-value的数据库&…

cookie、session、token、表单、json、jsonp、websocket、ajax都是什么

前后端数据交互的几种方式 1.cookie Cookie是服务器保存在客户端的一小段数据&#xff0c;&#xff08;使用Cookie的前提是客户端浏览器允许使用Cookie并对此做出相应的设置。&#xff09; cookie是一种存储在用户计算机上的小型数据文件&#xff0c;常用于在web应用程序中跟…

postgis导出shp中文乱码

使用postgis导出shp数据&#xff0c;发现中文内容乱码 网上搜到的解决方案&#xff0c;都是添加环境变量PGCLIENTENCODINGGBK 但是添加之后&#xff0c;不仅没有解决我的问题&#xff0c;反而导出直接报错了 经过个人简单分析之后&#xff0c;发现这个应该跟导入的数据编码格…

Jmeter(三十九) - 从入门到精通进阶篇 - Jmeter配置文件的刨根问底 - 上篇(详解教程)

宏哥微信粉丝群&#xff1a;https://bbs.csdn.net/topics/618423372 有兴趣的可以扫码加入 1.简介 为什么宏哥要对Jmeter的配置文件进行一下讲解了&#xff0c;因为有的童鞋或者小伙伴在测试中遇到一些需要修改配置文件的问题不是很清楚也不是很懂&#xff0c;就算修改了也是…