C++STL之string的使用

news2024/11/20 1:42:52

对于C语言中的字符串,我们只能使用char类型数组保存,并且是以'\0'结尾的.

操作起来非常不方便而且底层空间需要用户自己访问,非常造成容易越界访问.

这个时候,C++的STL中的string类就很好解决了这些.

目录

string的使用

1.string类对象的常见构造

 2. string类对象的容量操作

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

4. string类对象的修改操作

5.string类非成员函数


string的使用

string的使用主要是使用一些接口,下面将列出一些常用的接口使用.

1.string类对象的常见构造

当我们用string初始化对象时,可采用以下方法:

string()                                          构造空的string类对象,即空字符串

string(const char* s)                   用C-string来构造string类对象

string(size_t n,char c)                 string类对象中包含n个字符c

string(const string& s)                拷贝构造函数

看下列代码

void Teststring()
{
	string s1; // 构造空的string类对象s1
	string s2("hello hmylq"); // 用C格式字符串构造string类对象s2,即包含'\0'
	string s3(s2); // 拷贝构造s3
}

来分别看一下它们的值

这样就成功初始化了.

与从同时初始化的方法还有一种,就是赋值运算符重载"=",也可以进行初始化.

    string s = "lqhmy";

 2. string类对象的容量操作

size(重点)                                      返回字符串有效字符长度
length                                                 返回字符串有效字符长度
capacity                                             返回空间总大小
empty (重点)                                 检测字符串释放为空串,是返回true,否则返回false
clear (重点)                                    清空有效字符
reserve (重点)                               为字符串预留空间
resize (重点)                                  将有效字符的个数该成n个,多出的空间用字符c填充


void Teststring()
{
	// 注意:string类对象支持直接用cin和cout进行输入和输出
	string s("hello, hmylq!");
	cout << s.size() << endl;
	cout << s.length() << endl;
	cout << s.capacity() << endl;
	cout << s << endl; 
}

 capacity为当前底层空间容量,而size和length为当前字符串大小.

可以看到已经将字符串s的大小输出出来了.


void Teststring()
{
	string s("hello, hmylq!");
	// 将s中的字符串清空,注意清空时只是将size清0,不改变底层空间的大小
	s.clear();
	cout << s.size() << endl;
	cout << s.capacity() << endl;
}

此时clear是将字符串清空,大小变为0,但是容量不会改变.


void Teststring()
{
	string s("hello, hmylq!");
	// 将s中的字符串清空,注意清空时只是将size清0,不改变底层空间的大小
	s.clear();
	// 将s中有效字符个数增加到10个,多出位置用'a'进行填充
	// “aaaaaaaaaa”
	s.resize(10, 'a');
    cout << s.size() << endl;
	cout << s.size() << endl;
	cout << s.capacity() << endl;
}

 

 注意是将有效字符增加到10个,并不是容量!

可以看到resize已经成功把10个字符用’a'进行了填充.

resize还有注意的是,如果第二个参数不给值,会默认缺省值为'\0'

看下面的例子

void Teststring()
{
	string s("hello, hmylq!");
	// 将s中的字符串清空,注意清空时只是将size清0,不改变底层空间的大小
	s.clear();
	// 将s中有效字符个数增加到10个,多出位置用'a'进行填充
	// “aaaaaaaaaa”
	s.resize(10, 'a');
	// 将s中有效字符个数增加到15个,多出位置用缺省值'\0'进行填充
	// "aaaaaaaaaa\0\0\0\0\0"
	// 注意此时s中有效字符个数已经增加到15个
	s.resize(15);
	cout << s.size() << endl;
	cout << s.capacity() << endl;
	cout << s << endl;
}

 此时虽然字符串显示的是10个‘a',但是有效字符长度已经到了15,再向后插入字符将会在第16个字符进行插入.


void Teststring()
{
	string s("hello, hmylq!");
	// 将s中的字符串清空,注意清空时只是将size清0,不改变底层空间的大小
	s.clear();

	s.resize(10, 'a');
	// 将s中有效字符个数缩小到5个
	s.resize(5);
	cout << s.size() << endl;
	cout << s.capacity() << endl;
	cout << s << endl;
}

 可以看到有效长度已经缩小到了5个,但是总容量没有变化,而且这次是将有效字符长度缩小,所以会将多余的字符舍弃掉,只会留下前5个字符.


reserve

void Teststring()
{
	string s;
	// 测试reserve是否会改变string中有效元素个数
	s.reserve(100);
	cout << s.size() << endl;
	cout << s.capacity() << endl;
}

来看结果

可以看到reserve并没有改变size即有效元素的个数,只改变了容量大小,但我们开辟了100个空间,但为什么容量是111呢?

其实系统开辟空间默认是15个字节,当不满足需求时,将每次以1.5倍的速度扩容,直到大于或者等于指定的容量.


void Teststring()
{
	string s;

	s.reserve(100);
	// 测试reserve参数小于string的底层空间大小时,是否会将空间缩小
	s.reserve(50);
	cout << s.size() << endl;
	cout << s.capacity() << endl;
}

 结果如下:

可以看到空间并不会缩小,依然是111.

 与此同时有需要注意的几个点如下:

1. size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()。
2. clear()只是将string中有效字符清空,不改变底层空间大小。
3. resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。
4. reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserver不会改变容量大小。

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

operator[] (重点)            返回pos位置的字符,const string类对象调用
begin+ end                        begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器
rbegin + rend                     rbegin获取最后一个字符的迭代器 + rend获取第一个字符前一个位置的迭代器


范围for C++11支持更简洁的范围for的新遍历方式


 

void Teststring()
{
	string s1("hello lq");
	const string s2("Hello hmy");
	cout << s1 << " " << s2 << endl;
	cout << s1[0] << " " << s2[0] << endl;
	s1[0] = 'H';
	cout << s1 << endl;

	// s2[0] = 'h'; 代码编译失败,因为const类型对象不能修改
}

 可以看到我们直接用下标访问到string类中的第0个字符,当然还可以是别的下标位置.

获取到之后不仅可以使用,还可以进行修改.

例如我们将s1中的第一个字符'h'改成了'H'.

 非常的方便.


下面说string的遍历.

一共有三种方法:

需要注意的以下三种方式除了遍历string对象,还可以遍历时修改string中的字符,
另外以下三种方式对于string而言,第一种使用最多

1.for+operator[]

	for (size_t i = 0; i < s.size(); ++i)
		cout << s[i] << endl

2.迭代器

    string::iterator it = s.begin();
    while(it != s.end())
    {
        cout<<*it<<endl;
        ++it;
    }
    string::reverse_iterator rit = s.rbegin();
    while(rit != s.rend())
        cout<<*rit<<endl;

3.范围for

    for(auto& ch : s)
    {
        cout << ch << endl;
    }

4. string类对象的修改操作

push_back                   在字符串后尾插字符c
append                        在字符串后追加一个字符串
operator+= (重点)        在字符串后追加字符串str
c_str(重点)                  返回C格式字符串
find + npos(重点)        从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置
rfind                            从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置
substr                         在str中从pos位置开始,截取n个字符,然后将其返回


接下来看各接口的使用

void Teststring()
{
	string str;
	str.push_back(' '); // 在str后插入空格
	str.append("hello"); // 在str后追加一个字符"hello"
	str += 'h'; // 在str后追加一个字符'h'
	str += "lq"; // 在str后追加一个字符串"lq"
	cout << str << endl;
	cout << str.c_str() << endl; // 以C语言的方式打印字符串
}

 看输出结果

 可以发现都已经成功插入了

在string中push_back只能插入字符,append只能追加字符串,当然字符串可以是一个字母.

而+=既可以插入字符也可以插入字符串,所以我们平常使用+=居多.


void Teststring()
{
	// 获取file的后缀
	string file("string.cpp");
	size_t pos = file.rfind('.');
	string suffix(file.substr(pos, file.size() - pos));
	cout << suffix << endl;
}

我们都知道文件后缀是以 . 结尾

我们想获取文件的后缀名,首先要先找到.的位置,利用find或者rfind(这里使用rfind因为.一般都是偏后,所以是从后向前找),然后如果找到了,会返回这个位置的下标,否则返回npos,然后我们想获取.后面的内容,可以利用substr切取子串,从第6个位置开始,向后截取(总大小-6)个长度,即.后面的长度,这样就可以获得了.

其中的npos 是string中的一个静态成员变量        

   static const size_t npos = -1;

void Teststring()
{
	// 取出url中的域名
	string url("http://www.cplusplus.com/reference/string/string/find/");
	cout << url << endl;
	size_t start = url.find("://");
	//如果start等于了npos,说明没有找到,即这个url是非法的.
	if (start == string::npos)
	{
		cout << "invalid url" << endl;
		return;
	}
	//如果找到了,因为此时位置是在':'这个位置,所以必须将这个位置+=3跳过这个位置,此时的位置在"://www"中的第一个w位置
	start += 3;
	//然后开始寻找第一个/位置
	size_t finish = url.find('/', start);
	//此时从start到finsh之间的东西就是我们所需要的url域名
	string address = url.substr(start, finish - start);
	cout << address << endl;
}

上面的就是取出url域名的操作了

在这个操作中需要注意的是:

1. 在string尾部追加字符时,s.push_back(c) / s.append(1, c) / s += 'c'三种的实现方式差不多,一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。
2. 对string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留好。

5.string类非成员函数

operator+                                        尽量少用,因为传值返回,导致深拷贝效率低
operator>>                                   (重点) 输入运算符重载
operator<<                                   (重点) 输出运算符重载
relational operators(>,>=,<,<=,==)                     (重点) 大小比较

这里前三个前面已经说过了,主要说一下最后一个,就是字符串可以利用大于、小于、等于号等进行比较(按字典序比较)

void Teststring()
{
	string s1("abcde");
	string s2("bcdef");
	if (s1 > s2)
		cout << "s1 > s2" << endl;
	else if (s1 < s2)
		cout << "s1 < s2" << endl;
	else
		cout << "s1 == s2" << endl;
		
}

结果应当是s1<s2

符合了我们预期的结果.

这里想说明字符串可以直接利用运算符进行比较大小.

stl的string的使用就到此结束了,下一章将详细讲述它的模拟实现.

如果有疑问或者错误的地方,欢迎提出或指正哦.

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

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

相关文章

mqtt的使用与二次封装

前提&#xff1a;先安装Mosquitto并启动服务&#xff0c;可使用mqttx进行接收发送的测试。 Mosquitto以配置启动命令 mosquitto -c mosquitto.conf -v原文链接&#xff1a;mqtt的使用 本文为测试使用固无账号密码&#xff0c;可在原文查看 封装后实现效果&#xff0c;加入一个…

LeetCode题解 16(15,22) 三数之和,括号生成

文章目录三数之和(15)代码解答:括号生成(22)代码解答:三数之和(15) 该题是让从1个数组中找到和为0的不重复的三个数,这次我们使用排序和指针的方法来解决 先将该数组从小到大进行排序 Arrays.sort(nums);我们需要遍历一遍该数组,同时我们还要去重的操作(例如[-1,-1,-1,2],这里面…

helm本地debug template渲染小记

前提条件 1&#xff0c; 安装helm 2&#xff0c;要能连接的k8s 3&#xff0c;本地有完成charts文件目录 具体步骤 本文因为是在项目流程中helm渲染出的deployment语法报错或者最终生成的不符合预期&#xff0c;因此本地使用helm命令进行debug验证测试。 我们先看一下基本的c…

怎么把word里面的彩色图转化为灰度图,直接在word里面操作,无需转其他软件,超简单!(位图和矢量图都可以)

怎么把word里面的彩色图转化为灰度图&#xff0c;直接在word里面操作&#xff0c;无需转其他软件&#xff0c;超简单&#xff01;&#xff08;位图和矢量图都可以&#xff09; Microsoft Office Word是微软公司的一个文字处理器应用程序。它最初是由Richard Brodie为了运行DOS…

深入理解自编码器(用变分自编码器生成图像)

文章目录自编码器欠完备自编码器正则自编码器稀疏自编码器去噪自编码器收缩自编码器变分自编码器References内容总结自花书《Deep Learning》以及《Python 深度学习》。 自编码器 自编码器&#xff08;autoencoder&#xff09;是神经网络的一种&#xff0c;经过训练后能尝试将…

机器学习经典算法:决策树(2)

1. 概述 决策树&#xff08;Decision Tree&#xff09;是有监督学习中的一种算法&#xff0c;并且是一种基本的分类与回归的方法。决策树有两种&#xff1a;分类树和回归树。 决策树是用于分类和回归的工具&#xff0c;它将数据特征值拆分为决策节点处的分支&#xff08;例如&a…

六、Kubernetes核心技术Pod详解、实例

1、概述 Pod 是 k8s 系统中可以创建和管理的最小单元&#xff0c;是资源对象模型中由用户创建或部署的最 小资源对象模型&#xff0c;也是在 k8s 上运行容器化应用的资源对象&#xff0c;其他的资源对象都是用来支 撑或者扩展 Pod 对象功能的&#xff0c;比如控制器对象是用来管…

某大型政务网站的优化咨询案例(视频点播VOD+GZIP压缩+静态文件CDN+Redis缓存+全文索引)

2022年圣诞节到来啦&#xff0c;很高兴这次我们又能一起度过~ 这次分享关于一个对某大型政务网站的优化咨询的案例&#xff0c;发生在今年的下半年&#xff0c;已过去一段时间&#xff0c;并取得了良好的成果&#xff01;* 项目背景 某大型政务网站准备上线&#xff0c;需要…

08-Golang中的运算符

[TOC](Golang中的运算符运算符介绍算数运算符基本介绍细节说明关系运算符(比较运算符&#xff09;基本介绍细节说明逻辑运算符基本介绍细节说明赋值运算符基本介绍细节说明运算符优先级运算符介绍 运算符是一种特殊的符号&#xff0c;用来表示数据的运算、赋值和比较 1.算数运…

Vue事件处理的基本使用

前言 事件处理在vue中也是非常重要的一项技术&#xff0c;它类似于js的事件处理&#xff0c;但是也有不同&#xff0c;下面就简单介绍一下在vue中如何进行事件使用以及一些要点 1 事件基本使用 在这里我们使用单击事件为例&#xff0c;简单讲讲在vue中单击事件的编写以及细节…

最近面试遇到一个算法题,简单写一点。

第⼀题&#xff08;必答&#xff09; 请针对有重复数字的数组设计⼀个快排算法&#xff0c;⽐如&#xff1a;[34, 34, 89, 1, 1, 20, 12]&#xff0c;排序后结果为 [89,34,34,20,12,1,1] 第⼆题&#xff08;必答&#xff09; 请利⽤Redis 实现⼀个通⽤分布式锁&#xff0c;并…

技术进步、研发计划启动及政策支持 共促我国合成生物学市场容量加速扩张

合成生物学是对生物体进行有目标的设计、改造乃至重新合成&#xff0c;这一名词最早出现于DNA重组技术发展的上世纪70年代。合成生物学汇聚并融合了生命科学、工程学和信息科学等诸多学科&#xff0c;在天然产物合成、化学工业、生物能源、生物医药等诸多领域有广泛的应用前景。…

【Animejs】——Anime.js照片墙案例实现

目录 一、实现的效果&#xff1a; 二、实现js的具体步骤 1、需要实现的逻辑梳理 2、切换风格的逻辑 三、完整代码&#xff1a; 用js编写使用animejs实现图片复杂的切换效果 一、实现的效果&#xff1a; 点击——> <——箭头&#xff0c;实现不同动画效果的炫酷切换 …

【小5聊】C++ 输入矩阵数字,然后回环方式输出

C 输入矩阵数字&#xff0c;然后回环方式输出 1、题目内容 输入 第一行是两个m和n&#xff0c;分别代表矩阵的行数和列数。 第二行开始输入对应矩阵 输出 第二行回转输出。 相邻的两个整数之间用一个空格分开&#xff0c;行尾无空格 样例输入 5 6 4 8 9 4 5 6 1 2 5 6…

控制算法-PID算法总结-从公式原理到参数整定解析

目录 一、控制系统 1.1控制系统的分类 1.2 性能指标 二、PID算法的起源及特点 三、PID应用 四、PID公式原理 五、PID源码 六、PID整定方法 6.1 经验法 6.2 衰减曲线法 6.3 响应曲线法 参考文献&#xff1a; 一、控制系统 1.1控制系统的分类 分为开环控制、闭环控制和…

Java 8 Stream 从入门到进阶——像SQL一样玩转集合

0.阅读完本文你将会 了解Stream的定义和它的特征了解Stream的基础和高阶用法 1. 前言 在我们日常使用Java的过程中&#xff0c;免不了要和集合打交道。对于集合的各种操作有点类似于SQL——增删改查以及聚合操作&#xff0c;但是其方便性却不如SQL。 所以有没有这样一种方式…

【每日一题Day66】LC1754构造字典序最大的合并字符串 | 贪心 双指针模拟

构造字典序最大的合并字符串【LC1754】 You are given two strings word1 and word2. You want to construct a string merge in the following way: while either word1 or word2 are non-empty, choose one of the following options: If word1 is non-empty, append the fir…

10.2、Django入门--前台管理

文章目录1、URLconf 路由管理展示首页2、视图函数处理业务逻辑展示书籍的详细页3、模板管理实现好看的HTML页面3.1 模板引擎配置3.2 模板语法&#xff1a;变量3.3 模板语法: 常用标签3.4 主页与详情页前端HTML设计常用的HTML编写基础标题标签列表标签图片标签链接标签表格标签表…

耗时二周,万字总结Maven简明教程,与君共勉!

什么是Mavne Maven 是一个项目管理工具&#xff0c;它包含了一个项目对象模型 (POM&#xff1a;Project Object Model)&#xff0c;一组标准集合。由于 Maven 使用标准目录布局和默认构建生命周期&#xff0c;开发团队几乎可以立即自动化项目的构建基础设施。在多个开发团队环…

代码随想录训练营第60天|LeetCode 84.柱状图中最大的矩形

LeetCode 84.柱状图中最大的矩形 双指针 注意&#xff0c;双指针解法可行&#xff0c;但是在力扣上提交会超时。 以heights[i]为中心&#xff0c;用两个指针向两边扩散&#xff0c;直到heights[left]和heights[right]小于heights[i]为止&#xff0c;这样就构成了以left和rig…