C++ string类(2)—成员访问、插入、删除、替换、查找和交换操作

目录

一、成员访问

1、[ ]&at

2、front( )&back( )

 二、插入元素

三、删除元素

四、替换元素

五、查找元素 

1、查找第一次出现位置

2 、在指定范围内查找

六、交换字符串

七、c_str

八、rfind&substr


一、成员访问

1、[ ]&at

虽然二者功能一样,但[ ]比较常用。

int main()
{
	string s1("hello world");

	cout << s1[4] << endl;
	cout << s1.at(4) << endl;

	return 0;
}

访问越界[ ]会直接报错,.at( )会抛异常。

int main()
{
	string s1("hello world");

	try {
		s1.at(100);
	}
	catch (const exception& e) {
		cout << e.what() << endl;
	}

	return 0;
}

2、front( )&back( )

int main()
{
	string s1("hello world");

	cout << s1.back() << endl;
	cout << s1.front() << endl;

	return 0;
}

 二、插入元素

insert/erase不推荐经常使用,能少用就少用,因为他们可能都存在要挪动数据,效率低下。

指定位置插入字符串。

int main()
{
	string s1("world");
	s1.insert(0, "hello");
	cout << s1 << endl;

	return 0;
}

指定位置插入单个字符 

s1.insert(0, "w");

 

 两种方式指定位置插入空字符

使用单引号需要加上插入字符个数(第二个参数),使用双引号不需要。

int main()
{
	string s1("world");

	s1.insert(2, 1, ' ');
	s1.insert(3, " ");
	cout << s1 << endl;

	return 0;
}

 

 插入可以借助迭代器的begin()和end()获取位置。

s1.insert(s1.begin()+2, ' ');
s1.insert(s1.end() - 1, ' ');

 

三、删除元素

 insert/erase不推荐经常使用,能少用就少用,因为他们可能都存在要挪动数据,效率低下。 

删除指定位置指定长度字符。 

int main()
{
	string s2("hello world");
	s2.erase(5, 1);
	cout << s2 << endl;

	return 0;
}

也可以使用迭代器。 

    s2.erase(s2.begin() + 5);

 

 如果长度大于字符串长度或者缺省,则删除指定位置开始一直到最后的字符。

	s2.erase(5, 30);
    s2.erase(5);

 

四、替换元素

replace()函数的第一个参数是替换的起始位置,第二个参数是要替换的字符数,第三个参数是替换的字符串。 

int main()
{
	string s1("hello world");
	s1.replace(5, 1, "&&&&");
	cout << s1 << endl;

	return 0;
}
  • 首先,代码中的第一行是被注释掉的,表示字符串s1被初始化为"hello world"。这是一个注释行,不会被执行。
  • 然后,使用s1.replace(5, 1, "&&&&")函数调用来替换字符串s1中从索引位置5开始的1个字符,将其替换为"&&&&"。
  • 接下来,使用cout对象和<<运算符将修改后的字符串s1输出到标准输出流。

使用replace时,空间不够扩容,还要移动数据。 

五、查找元素 

1、查找第一次出现位置

find()用于在字符串中查找指定子串的第一个出现位置。

find()函数有多个重载版本,其中最常用的版本接受一个参数,即要查找的子串。它返回一个整数值,表示子串在字符串中的位置索引。如果找到了子串,则返回第一个匹配的位置索引;如果未找到子串,则返回一个特殊的值std::string::npos

int main()
{
	string s1("hello world I love you");
	size_t pos = s1.find(' ');
	while (pos != string::npos) {
		s1.replace(pos, 1, "***");
		pos = s1.find(' ');
	}
	cout << s1 << endl;
	return 0;
}

我们可以对上述程序进行优化。

int main()
{
	string s1("hello world I love you");
	size_t num = 0;
	for (auto ch : s1) {
		if (ch == ' ')
			++num;
	}
	s1.reserve(s1.size() + 2 * num);
	size_t pos = s1.find(' ');
	while (pos != string::npos) {
		s1.replace(pos, 1, "***");
		pos = s1.find(' ',pos+3);
	}
	cout << s1 << endl;
	return 0;
}

首先,在代码中创建了一个名为s1的字符串对象,并将其初始化为"hello world I love you"。

然后,使用一个循环遍历字符串s1中的每个字符。在循环中,如果当前字符是空格,则将计数器num加1。

接下来,使用s1.reserve(s1.size() + 2 * num)函数调整字符串s1的容量,以便能够容纳替换后的字符串。这样做是为了避免在替换过程中频繁地重新分配内存,提高性能

然后,使用s1.find(' ', pos)函数来查找字符串s1中下一个空格的位置。如果找到了空格,将其位置存储在变量pos中。

接下来,使用s1.replace(pos, 1, "***")函数将找到的空格替换为三个星号"***"。这样做会修改字符串s1中的内容。

然后,使用pos = s1.find(' ', pos + 3)来查找下一个空格的位置,从上一个空格的位置加3开始查找。这样做是为了避免重复替换已经被替换过的空格

循环会一直执行,直到没有更多的空格被找到。

最后,使用cout对象和<<运算符将修改后的字符串s1输出到标准输出流。

 还可以使用+=运算符进一步优化。

int main()
{
	string s1("hello world I love you");
	string newStr;
	size_t num = 0;
	for (auto ch : s1) {
		if (ch != ' ')
			++num;
	}
	newStr.reserve(s1.size() + 2 * num);
	for (auto ch : s1) {
		if (ch != ' ')
			newStr += ch;
		else
			newStr += "***";
	}
	s1 = newStr;
}

与之前的版本相比,这段程序是对第一段程序的改进版本,具有以下特点和优点: 

  1. 更简洁:第二段程序使用了更简洁的方法来替换字符串中的空格,避免了使用循环和查找函数。

  2. 更高效:第二段程序只需遍历一次原始字符串,而不是使用循环和查找函数多次遍历。这样可以减少时间复杂度,提高程序的执行效率。

  3. 更易读:第二段程序使用了更直观的方式来替换空格,通过判断字符是否为空格来决定添加字符还是添加"***"。这样代码更易读懂,减少了冗余的操作。

  4. 更节省内存:第二段程序使用了新的字符串newStr来存储替换后的结果,避免了对原始字符串s1进行频繁的修改。这样可以减少内存的使用,提高程序的效率。

2 、在指定范围内查找

六、交换字符串

int main()
{
	string s1("hello world");
	string s2("xxxxx");
	s1.swap(s2);
	cout << s1 << endl;
	cout << s2 << endl;

	swap(s1, s2);
	cout << s1 << endl;
	cout << s2 << endl;
}

这段程序中的两个swap函数调用有以下区别:

  1. s1.swap(s2):这是成员函数形式的swap调用,它将s1s2两个字符串对象进行交换。在交换后,s1的值变为"xxxxx",s2的值变为"hello world"。这种形式的swap函数是通过成员函数调用来实现的。

  2. swap(s1, s2):这是非成员函数形式的swap调用,它通过传递s1s2两个字符串对象作为参数来进行交换。在交换后,s1的值变为"hello world",s2的值变为"xxxxx"。这种形式的swap函数是通过非成员函数调用来实现的。

总结起来,这两个swap函数的功能是一样的,都是用于交换两个字符串对象的值。区别在于调用方式不同,一个是通过成员函数调用,一个是通过非成员函数调用。使用哪种形式的swap函数取决于个人偏好和代码风格。

 

七、c_str

int main()
{
	string s1("hello world");
	cout << s1 << endl;
	cout << s1.c_str() << endl;

	return 0;
}
  1. cout << s1 << endl;:这行代码将字符串对象s1直接输出到标准输出流cout中。它会输出s1的内容,即字符串 "hello world"。

  2. cout << s1.c_str() << endl;:这行代码使用了字符串对象s1c_str()成员函数。c_str()函数返回一个指向以空字符结尾的字符数组(C风格字符串)的指针。然后,该指针被传递给cout输出流进行输出。它也会输出s1的内容,即字符串 "hello world"。

区别在于输出的方式不同。第一行直接输出字符串对象s1的内容,而第二行使用了c_str()函数将字符串对象转换为C风格字符串后输出。通常情况下,直接输出字符串对象更为简洁和方便。

int main()
{
	string s1("hello world");
    cout << s1 << endl;
	cout << s1.c_str() << endl;
	s1 += '\0';
	s1 += '\0';
	s1 += "xxxxx";
	cout << s1 << endl;
	cout << s1.c_str() << endl;

	return 0;
}

可以看到,通过对s1进行修改操作后,输出结果中的空字符('\0')在字符串对象s1的输出中仍然存在,但在c_str()函数返回的C风格字符串中被忽略了。这是因为c_str()函数会将字符串以空字符结尾,而在输出时遇到空字符就会停止输出。 

我们逐步解释为什么输出结果会有所不同。

初始状态下,s1的值为"hello world"。

  1. cout << s1 << endl;:输出s1的内容,即字符串 "hello world"。

  2. cout << s1.c_str() << endl;:输出s1的C风格字符串表示,即 "hello world"。

  3. s1 += '\0';:在s1末尾添加一个空字符('\0'),此时s1的值变为 "hello world\0"。

  4. s1 += '\0';:再次在s1末尾添加一个空字符('\0'),此时s1的值变为 "hello world\0\0"。

  5. s1 += "xxxxx";:将字符串 "xxxxx" 追加到s1的末尾,此时s1的值变为 "hello world\0\0xxxxx"。

  6. cout << s1 << endl;:输出s1的内容,即 "hello world\0\0xxxxx"。

  7. cout << s1.c_str() << endl;:输出s1的C风格字符串表示,即 "hello world"。这里需要注意,c_str()函数返回的是以空字符结尾的字符数组,输出时遇到第一个空字符就会停止输出。

八、rfind&substr

rfind函数用于在一个字符串中从后往前搜索指定的子字符串,并返回子字符串的位置。

它的语法如下:

size_t rfind(const string& str, size_t pos = string::npos) const;

str是要搜索的子字符串,pos是搜索的起始位置,默认为string::npos,表示从字符串的末尾开始搜索。

substr函数用于从一个字符串中提取子字符串。它的语法如下:

string substr(size_t pos = 0, size_t len = string::npos) const;

其中,pos是要提取的子字符串的起始位置,默认为0,len是要提取的子字符串的长度,默认为string::npos,表示提取从起始位置到字符串末尾的所有字符。

接下来看下面代码:

int main()
{
	string file("string.cpp.tar.zip");
	size_t pos = file.rfind('.');
	if (pos != string::npos)
	{
		string suffix = file.substr(pos);
		cout << suffix << endl;
	}

	return 0;
}

 

这段代码的目的是提取文件名中的后缀名。

首先,定义了一个字符串file,其中包含了一个文件名string.cpp.tar.zip

然后,使用rfind函数从后往前搜索.字符的位置,并将结果保存在变量pos中。如果找到了.字符,则pos的值不等于string::npos

接下来,通过判断pos的值是否不等于string::npos,来确定是否找到了.字符。如果找到了,则使用substr函数从pos位置开始提取子字符串,并将结果保存在变量suffix中。

最后,将提取到的后缀名输出到标准输出流cout中,然后换行。

在这个例子中,输出结果为.zip,因为.字符后面的部分就是文件的后缀名。

 从URL中提取主机地址:

int main()
{
	string url("http://www.cplusplus.com/reference/string/string/find/");
	cout << url << endl;
	size_t start = url.find("://");
	if (start == string::npos)
	{
		cout << "invalid url" << endl;
	}

	start += 3;
	size_t finish = url.find('/', start);
	string address = url.substr(start, finish - start);
	cout << address << endl;


	return 0;
}

使用find函数搜索字符串url中第一次出现的子字符串"://"的位置,并将结果保存在变量start中。如果找不到该子字符串,则start的值等于string::npos

接下来,通过判断start的值是否等于string::npos,来确定是否找到了"://"子字符串。如果没有找到,则输出"invalid url",表示URL无效。

如果找到了"://"子字符串,则将start的值增加3,以跳过"://"部分,然后使用find函数搜索从start位置开始的下一个'/'字符的位置,并将结果保存在变量finish中。

最后,使用substr函数从start位置开始,提取从startfinish之间的子字符串,并将结果保存在变量address中,将提取到的主机地址输出到标准输出流cout中,然后换行。

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

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

相关文章

【微信小程序】上传头像 微信小程序内接小程序客服

这里写目录标题 微信小程序上传头像使用button按钮包裹img 微信小程序内接小程序客服使用button按钮跳转客服 微信小程序上传头像 使用button按钮包裹img 原本思路是只使用image标签再加上chooseImg&#xff0c;但发现使用button标签上传头像这种方法更实用。微信小程序文档上…

栈实现队列,力扣

题目地址&#xff1a; 232. 用栈实现队列 - 力扣&#xff08;LeetCode&#xff09; 难度&#xff1a;简单 今天刷栈实现队列&#xff0c;大家有兴趣可以点上看看题目要求&#xff0c;试着做一下。 题目&#xff1a; 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支…

简单句子成分、阅读技巧

四、段落的主旨题&#xff1a;问这一段讲了什么&#xff08;一般都在段落的第一句话或最后一句话&#xff09; 词汇题的答案一般都在生词的上一句或者下一句 做题步骤&#xff1a; 1、先标段落 2、看题&#xff0c;划出关键词 3、去原文定位&#xff0c;标注中文意思 4、第一遍…

类和对象——(5)定义对象数组

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd; 芳华没有草稿纸&#xff0c;我们永久不…

异常(C++)

异常 前言一、程序的错误分类二、异常1. 概念2. 捕获异常的关键字和格式3. 异常的使用异常的原则异常再抛出异常说明注意事项 4. 自定义异常体系5. C标准库的异常体系 三、总结 前言 在程序运行时经常碰到一些错误&#xff0c;例如年龄、身高不能为负&#xff0c;除数为0等&…

阿里微服务质量保障系列:性能监控最佳实践

建设一体化性能监控平台 随着互联网技术的不断发展&#xff0c;企业的业务规模和复杂度也在不断增加。为了保证业务的稳定性和可靠性&#xff0c;企业需要对其系统进行全面的性能监控。而一体化性能监控就是一种集成了多种监控工具和技术的综合性监控方案&#xff0c;可以帮助…

PPT设置背景颜色

问题描述&#xff1a;PPT如何设置背景颜色&#xff1f; 问题解决&#xff1a;设计→设置背景格式→颜色→蓝色&#xff08;最好选择看着比较舒服的颜色&#xff09;

软件设计模式原则(三)单一职责原则

单一职责原则&#xff08;SRP&#xff09;又称单一功能原则。它规定一个类应该只有一个发生变化的原因。所谓职责是指类变化的原因。如果一个类有多于一个的动机被改变&#xff0c;那么这个类就具有多于一个的职责。而单一职责原则就是指一个类或者模块应该有且只有一个改变的原…

linux下安装nginx

第一步&#xff1a;压缩包 准备压缩包&#xff0c;最好准备一个稳定的版本&#xff1a;下载地址 我这边选用的是1.24.0双版本号 第二步&#xff1a;解压 在相对应的目录下&#xff0c;执行命令&#xff1a;tar -zxvf nginx-1.18.0.tar.gz 第三步&#xff1a;配置\编译 推荐…

【vue】尚硅谷vue3学习笔记

Vue3快速上手 1.Vue3简介 2020年9月18日&#xff0c;Vue.js发布3.0版本&#xff0c;代号&#xff1a;One Piece&#xff08;海贼王&#xff09;耗时2年多、2600次提交、30个RFC、600次PR、99位贡献者github上的tags地址&#xff1a;https://github.com/vuejs/vue-next/release…

图论|并查集理论基础 1971. 寻找图中是否存在路径

什么是并查集 并查集是一种数据结构&#xff0c;用于处理一些不交集的合并及查询问题。它支持两种操作&#xff1a; 查找&#xff08;Find&#xff09;&#xff1a;确定某个元素属于哪个子集。它可以用来判断两个元素是否属于同一个子集。 合并&#xff08;Union&#xff09;&…

Button初了解

Button 由TextView派生而来&#xff0c;二者的区别有&#xff1a; Button有默认的按钮背景&#xff0c;TextView默认无背景Button的内部文本默认居中对齐&#xff0c;而TextView的默认靠左对齐2023年以前&#xff0c;Button默认将英文换为大写&#xff0c;而TextView保持原始的…

springboot助农管理系统

springboot助农管理系统 成品项目已经更新&#xff01;同学们可以打开链接查看&#xff01;需要定做的及时联系我&#xff01;专业团队定做&#xff01;全程包售后&#xff01; 2000套项目视频链接&#xff1a;https://pan.baidu.com/s/1N4L3zMQ9nNm8nvEVfIR2pg?pwdekjv 提…

虚拟化逻辑架构: VM VirtualBox 指定6.0.24版本开启硬件辅助虚拟化功能

目录 一、实验 1.安装VM VirtualBox-6.0.24 2.安装VM VirtualBox-6.1.26 3.再次重新安装VM VirtualBox-6.0.24 二、问题 1.系统开机报错 2.Ubuntu系统无法自适应VM VirtualBox系统边框 3.VirtualBox如何开启无缝模式 3.Ubuntu如何查询软件是否已经安装 一、实验 1.安…

Redis之五大基础数据类型(详细总结 面试必备)

Redis之五大基础数据类型 Redis 共有 5 种基本数据类型&#xff1a;String&#xff08;字符串&#xff09;、List&#xff08;列表&#xff09;、Set&#xff08;集合&#xff09;、Hash&#xff08;散列&#xff09;、Zset&#xff08;有序集合&#xff09;。 这 5 种数据类…

二叉树在线OJ

二叉树的构建及遍历 本题目的要求是&#xff1a; 输入一个数组&#xff0c;里面存放了若干个字符&#xff0c;#代表了空指针&#xff0c;数组中的顺序是 是先序遍历&#xff0c;然后要求你用中序输出 首先我们要做的就是构造结构体&#xff1a; typedef struct TreeNode {char…

leetcode:232. 用栈实现队列

一、题目 原题链接&#xff1a;232. 用栈实现队列 - 力扣&#xff08;LeetCode&#xff09; 函数原型&#xff1a; typedef struct //我的队列结构定义 { } MyQueue; MyQueue* myQueueCreate() //我的队列创建及其初始化 void myQueuePush(MyQueue* obj, int x) //我的队…

shell编程awk命令详解(超详细)

文章目录 前言一、awk命令介绍1. awk命令简介2. awk命令的基本语法3. 常用的awk命令选项4. 常用的awk内置变量 二、awk命令示例用法1. 打印整行2. 打印特定字段3. 根据条件筛选行4. 自定义分隔符5. 从文件中读取awk脚本 总结 前言 awk命令是一种强大的文本处理工具&#xff0c…

【理解ARM架构】中断处理 | CPU模式

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《理解ARM架构》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 目录 &#x1f35c;中断&#x1f368;GPIO中断代码实现 &#x1f35c;CPU&#x1f368;CONTROL…

Java 数据结构篇-用链表、数组实现队列(数组实现:循环队列)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 队列的说明 1.1 队列的几种常用操作 2.0 使用链表实现队列说明 2.1 链表实现队列 2.2 链表实现队列 - 入栈操作 2.3 链表实现队列 - 出栈操作 2.4 链表实现队列 …