【C++初阶】STL-string的使用

news2024/9/30 7:17:56

文章目录

  • 一.string初识
    • 1.STL简介
      • a.STL的组成
      • b.STL和string的关系
    • 2.basic_string
  • 二.构造函数
  • 三.三种遍历方式
  • 四.容量相关的函数
    • 1.size()
    • 2.reserve()–调整容量
    • 3.resize()–调整size
  • 五.字符串的增删查改
    • 1.assign
    • 2.replace
    • 3.find()
    • 4.substr()
    • 5.insert()
    • 6.相关应用
      • a.替换空格:
      • b.取出文件后缀:
  • 六.字符串操作函数
    • 1.c_str
    • 2.getline()

一.string初识

1.STL简介

a.STL的组成

STL(standard template libaray-标准模板库):是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且 是一个包罗数据结构与算法的软件框架。

image-20221126230014736

网上有句话说:“不懂STL,不要说你会C++”。STL是C++中的优秀作品,有了它的陪伴,许多底层的数据结构 以及算法都不需要自己重新造轮子,站在前人的肩膀上,健步如飞的快速开发。

b.STL和string的关系

推荐一个学习C++的一个文档网站:C++文档说明,看文档也是一种工作必备能力哦

历史上,string出现的比STL出现的早,但是因为功能上string和STL中的容器很像,所以把string纳入到STL中。

2.basic_string

C++plusplus以后我用的时候就称为C++文档了,希望大家理解,C++文档中

image-20221126231347141

image-20221126231533584

所以原理上,下面两种方式都是定义一个字符串:

	string str1;
	basic_string<char> str2;

那么是否还可以通过其他的类型来完成类模板的实例化?可以!

image-20221126231658935

上述有多种模板实例化的模板类,那和字符集编码有关。我们之所以用的最多的是string那是因为我们通常使用到的是utf-8字符集编码,所以我们一般使用basic_string< char >存储utf-8字符组成的字符串; 如果我们使用的是utf-16字符集编码,我们继续使用basic_string< char >存储utf-16组成的字符串就会出现乱码,所以我们应该使用basic_string< char16_t >

二.构造函数

构造函数的这几种构造方式要非常熟悉,因为string类的其他接口也有用到类似形式的构造参数,我称之为参数可变(个人叫法)

构造函数说明
string()重要,无参构造
string (const char* s)重要,常量字符串构造
string (const string& str)重要,拷贝构造
string (size_t n, char c)了解,n个c字符构造
string (const char* s, size_t n)了解,s字符串前n个构造
string (const string& str, size_t pos, size_t len = npos)了解,str对象的pos下标,跨度len的构造
string (InputIterator first, InputIterator last)了解,迭代器相关
  • image-20221126235648068

ps:string类的接口由100多个,但是我们学习的目标是:熟练掌握常用的20余个,其他的要用的时候翻阅文档查看学习使用即可.

void test1()
{
	string str1;//空字符串
	string str2("hello");//"hello"
	string str3(str2);//"hello"

	string str4(5, 'x');//"xxxxx"
	string str5("XXYYZ", 4);//"XXYY"
	string str6(str5, 0, 2);//"XX"
}

image-20221127000801303

三.三种遍历方式

1.下标 + [ ]

2.范围for:实际上auto是模仿其他语言的,底层实现也是迭代器

3.迭代器:迭代器可能可能是指针,也有可能不是指针,但是它使用起来很像指针。(iterator具体实现得看后面了,这里会用就行,不必深究)

void test2()
{
	string str("123456");
	//1. 下标+[] 
	for (size_t i = 0; i < str.size(); ++i)
	{
		str[i]++;
		cout << str[i] << " ";
	}
	cout << endl;
	//2. 范围for
	for (auto& e : str)
	{
		e--;
		cout << e << " ";
	}
	cout << endl;
	//3. 迭代器
	string::iterator it = str.begin();
	while (it != str.end())
	{
		(*it)++;
		cout << *it << " ";
		it++;
	}
	cout << endl;
}

既然第一种下标加方括号的形式既支持可读又可写,为什么我们还要学习迭代器呐?

那是因为迭代器是一种通用的访问形式,在string和vector中由于底层实现都是一种顺序表,而顺序表是支持下标加方括号的形式随机访问的,但是如果我没学到后面的list等,下标加方括号显然就不适用了,这个时候叠加器的优点才真正显示出来。

那么接下来我将给大家介绍一下几种迭代器:

  1. 正向迭代器和反向迭代器
  2. const迭代器

上面的迭代器都可以两两组合,比如正向非const迭代器,正向const迭代器等

  • 反向迭代器

image-20221127195743771

  • const迭代器

image-20221127201155634

这里的string::const_iterator是不是使用起来不是那么方便,那么我们可以选择使用auto自动识别类型。

  • 反向const迭代器

上面讲一下反向const迭代器这种类型名最长的组合形式:

image-20221127201559731

到了这里我们也了解到了什么是const的迭代器,什么是非const迭代器,那么为什么迭代器要s设计出const版本和非const版本呢?这是和它的功能有关,他必须要支持读和写的功能。

operate[]运算符重载函数其实设计出了const和非const两种版本

size()函数功能上只需要具备读,所以也就只设计出const版本

push_back()函数功能上只需要具备写,所以也就只设计出非const版本

image-20221127202848934

四.容量相关的函数

函数说明
size()返回字符串有效字符长度
capacity()返回空间总大小
clear()清空有效字符
reserve(n)仅改变capacity(),常用于扩容
resize(n)改变size(),可能改变capacity(), 将有效字符的个数该成n个,多出的空间用字符c填充
empty()检测字符串释放为空串,是返回true,否则返回false

1.size()

或许你学了许久C++都不知道为什么C++既有size()又有length(),它们的结果明明是一样的。

image-20221127203934579

原因:string设计早于STL,STL有自己的一套,也就包含size()

string有它的一套,也就是length(),作为STL的设计者把string加入到STL中的时候,为了向前兼容,就保留了原来的一套。

那么我们究竟在使用的时候推荐使用size()还是length()呐?用之疑,肯定是优先选择size(),因为他能和后面的其他容器保持一定的统一性,字符串你能使用length(),但是对于二叉树这种结构能使用length()吗?显然不可以。

另外通过上面的图的运行结果,我们也可以看出size()和length(),计算出的结果都是有效字符个数,是不包含斜杠铃的,因为‘\0’是字符串结尾的标记字符

ps:vs下,capacity()计算的容量结果也没有包含‘\0’

2.reserve()–调整容量

void test6()
{
	string str;
	size_t sz = str.capacity();
	cout << "InitCapacity:"<< sz << endl;
	for (int i = 0; i < 100; i++)
	{
		str.push_back('c');
		if (sz != str.capacity())
		{
			sz = str.capacity();
			cout << "capacity changed:" << sz << endl;
		}
	}
}

image-20221127205654865

首先我们回顾一下:vs下,capacity()计算的容量结果是不包含‘\0’的(包含还是不包含和具体实现有关),那我们可以到Linux下试一试:

image-20221127210736375

对比发现,vs下扩容倍数大概是1.5倍

linux的g++下,扩容倍数大概是2倍(这点上还是linux友好点)

那我为什么要和大家讲上面的这些东西呐?那是想和大家说明vs和Linux下的g++下,扩容是有代价的,所以如果我们在已知大概容量的情况下可以使用reserve() 提前开好适当大小的空间,从而减少扩容。

void test6()
{
	string str;
	str.reserve(100);
	size_t sz = str.capacity();
	cout << "InitCapacity:"<< sz << endl;
	for (int i = 0; i < 100; i++)
	{
		str.push_back('c');
		if (sz != str.capacity())
		{
			sz = str.capacity();
			cout << "capacity changed:" << sz << endl;
		}
	}
}

image-20221127212116460

可以看到扩容次数明显减少了!!!!

但是在vs下有一个奇怪的现象,知道就好,不必深究:

image-20221127212618671

3.resize()–调整size

作用:将有效字符的个数该成n个,多出的空间用字符c填充

image-20221127213449826

void test8()
{
	string str("hello world");
	//str.size()==11   str.capacity()==15

	str.resize(5);
	cout << "情况1: " << endl;
	cout << str.size() << endl;
	cout << str.capacity() << endl;
	cout << str << endl << endl;

	str.resize(13,'a');
	cout << "情况2: " << endl;
	cout << str.size() << endl;
	cout << str.capacity() << endl;
	cout << str << endl << endl;

	str.resize(20,'b');
	cout << "情况3: " << endl;
	cout << str.size() << endl;
	cout << str.capacity() << endl;
	cout << str << endl << endl;

}

image-20221127215243270

五.字符串的增删查改

函数说明
push_back()头插
pop_back()头删
insert()在pos位置插入,插入部分的种类类似构造
erase()在pos位置删除
opearator+=()重要,在字符串后追加字符串str
assign()清空后重新赋新值,赋值部分的种类类似构造
replace()替换
find()查找子串,返回下标
substr()返回子串

1.assign

功能和赋值类似

string& assign (const string& str);

参数可变

image-20221202163645124

演示:

void test2()
{
	string str1 = "hello world";
	string str2 = "bit";
	str1.assign(str2);//"bit"

	str1.assign("C++");//"C++"
	str1.assign("C++", 0, 1);//"C"
	str1.assign(str2, 1, 1);//"i"
	str1.assign(3, 'x');//"xxx"
	cout << str1 << endl;
}

2.replace

功能:把从pos位置开始,替换跨度为span的字符串

,替换为str2(可变)

string& replace (size_t pos,  size_t len,  const string& str);

第三个参数可变

image-20221202164410177

演示:

void test3()
{
	string str1 = "hello world";
	str1.replace(1, 3, "bit");//"hbito world"
	cout << str1 << endl;

	string str2 = "song";
	str2.replace(0, 1, "yong", 0, 3);//"yonong"
	cout << str2 << endl;


	string str3 = "libai";
	str3.replace(1, 2, 5, 'x');//"lxxxxxai"
	cout << str3 << endl;
}

3.find()

功能:从pos位置开始查找子串(字符串或字符),找到返回下标,没找到返回npos

size_t find (const string& str, size_t pos = 0) const;

image-20221202170601034

ps:pos参数缺省,默认从0开始找(默认是全局查找)

说明缺省值:npos
static const size_t npos = -1;
表面npos是-1,但是因为类型是size_t,无符号整数类型,所以实际上是非常大的数

image-20221202172050520

void test5()
{
	string str1 = "hello world C++";
	size_t pos = str1.find(' ',11);//11,ps:下标为11是在d的后一个位置' ',也就是我们要找的‘ '的位置
	pos = str1.find("ll");//2
	pos = str1.find("world", 3);//6
	cout << pos << endl;
}

image-20221202171532720

4.substr()

功能:返回从pos位置,跨度为span的字符串

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

image-20221202165657075

ps:substr()函数是全缺省的,默认从0开始找(默认是全局查找),跨度为npos

void test4()
{
	string str1 = "hello world";
	string str2=str1.substr();//"hello world"

	str2 = str1.substr(1);//"ello world"

	str2 = str1.substr(1, 1);//"e"

	cout << str2 << endl;
}

5.insert()

功能:从pos位置开始,插入字符串或字符

string& insert (size_t pos, const string& str);

image-20221202171724907

第二个参数可变

演示:

void test6()
{
	string str1 = "hello world";
	str1.insert(0, "song");//相当于头插  --"songhello world"
	str1.insert(str1.size(), "libai");//'\0'的位置就是str1.size(),他的下标看他前面有多少个字符--"songhello worldlibai"
	string str2 = "C++";
	str1.insert(1, str2);//"sC++onghello world"
	
	cout << str1 << endl;
}

由数据结构我们感知到这insert类头插因为大量挪动数据,效率肯定不高~

6.相关应用

a.替换空格:

方法1:

void test7()
{
	string str1 = "hello world C++  ";
	size_t pos = str1.find(' ');
	while(pos != string::npos)
	{
		str1.replace(pos, 1, "%20");
		pos = str1.find(' ', pos + 3);
	}
	cout << str1 << endl;
}

方法2:以空间换时间

void test8()
{
	string str1 = "hello world C++  ";
	string ans;
	ans.reserve(str1.size());
	for (int i = 0; i < str1.size(); i++)
	{
		if (str1[i] != ' ')
			ans += str1[i];
		else
			ans += "%20";
	}
	cout << ans << endl;
}

变式:如果我要把“abcdeffcadgascg”这字符串中的‘a’和‘c’字符都换成“*”,我再使用find就搞不定了,我得使用名字起的很怪的函数接口find_first_of()

作用:在str1中查找出在str2字符串中出现的任意一个字符,返回下标

void test12()
{
	string str1 = "abcdefccdefa";
	size_t pos = str1.find_first_of("ac", 0);
	while (pos != string::npos)
	{
		str1.replace(pos, 1, "*");
		pos = str1.find_first_of("ac", pos + 1);
	}
	cout << str1 << endl;
}

image-20221202201241483

b.取出文件后缀:

void test10()
{
	//要求取出后缀
	string str1 = "test.cpp";
	size_t pos = str1.find('.');
	if (pos != string::npos)//if找到了
	{
		string ans = str1.substr(pos);
		cout << ans << endl;
	}
}

但是如果像Linux中的一些文件后缀:.zip.tgz

这时候find()就搞不定了,我们得用rfind,倒着找,才能找到.tgz

void test11()
{
	string str1 = "test.zip.tgz";
	size_t pos = str1.rfind('.');
	if (pos != string::npos)//if找到了
	{
		string ans = str1.substr(pos);
		cout << ans << endl;
	}
}

六.字符串操作函数

1.c_str

功能:返回string类成员变量中_str的地址

const char* c_str() const;

一般在C和C++结合使用的时候能使用到,比如用C语言打开文件

void test9()
{
	string file("test.cpp");
	FILE* fp = fopen(file.c_str(), "r");

	char ch = fgetc(fp);
	while (ch != EOF)
	{
		cout << ch;
		ch = fgetc(fp);
	}
	fclose(fp);
}

2.getline()

功能:cin会读取到键盘输入的数据,当读到空格或者换行的时候,会停止读,所以当我们要键盘输入的字符串是带有空格的时候,不能再使用cin,而是采用getline,这在oj题中经常出现!

istream& getline (istream& is, string& str)

oj题目作为实例:

题目链接:https://www.nowcoder.com/practice/8c949ea5f36f422594b306a2300315da?tpId=37&&tqId=21224&rp=5&ru=/activity/oj&qru=/ta/huawei/question-ranking

#include <iostream>
#include <string>
using namespace std;

int main() {
    string str;
    //cin>>str;
    getline(cin,str);
    size_t pos=str.rfind(' ');
    cout<<str.size()-(pos+1)<<endl;
    return 0;
}

另外一个注意的点就是:左闭右开才是个数!

相减得到之间个数,左边的值计算在个数内,右边的值不计算在个数内

image-20221202203323395

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

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

相关文章

【Redis-08】面试题之Redis数据结构与对象-RedisObject(上篇)

Redis本质上是一个数据结构服务器&#xff0c;使用C语言编写&#xff0c;是基于内存的一种数据结构存储系统&#xff0c;它可以用作数据库、缓存或者消息中间件。 我们经常使用的redis的数据结构有5种&#xff0c;分别是&#xff1a;string(字符串)、list(列表)、hash(哈希)、s…

string类的模拟实现

目录 一、浅拷贝、深拷贝 二、传统版本写法的String类 三、现代版本写法的String类 四、String类的模拟实现 一、浅拷贝、深拷贝 构造 //构造函数String(const char* str ""){if (nullptr str){assert(false);return;}_str new char[strlen(str) 1];strcpy(_s…

使用 Pandas 和 SQL 进行实用数据分析,让我们用 pandas 和 SQL 进行数据分析并实际理解它们(教程含数据csv)

Pandas是一种快速、强大、灵活且易于使用的开源数据分析和操作工具, 构建于 Python 编程语言之上。 SQL代表结构化查询语言。SQL 允许您从 RDBMS(关系数据库管理系统)访问数据,并可用于数据分析。 Pandas 和 SQL 都广泛用于数据分析。 在这篇博客中,我们将使用pandas和…

做好自己安全第一责任人 嘀嗒全面上线安全带智能语音提醒

2022年12月2日是第十一个“全国交通安全日”&#xff0c;今年主题为“文明守法 平安回家”。 当天&#xff0c;嘀嗒出行启动主题为“共建三方安全观&#xff0c;安全要靠你我他”共塑行动&#xff0c;倡导平台、用户、行业各方形成合力&#xff0c;共塑共创安全文明的新出行之路…

简单的PCI总线INTx中断实现流程

一个简单的PCI总线INTx中断实现流程,如下图所示。 1. 首先,PCI设备通过INTx边带信号产生中断请求,经过中断控制器(Interrupt Controller,PIC)后,转换为INTR信号,并直接发送至CPU; 2. CPU收到INTR信号置位后,意识到了中断请求的发生,但是此时并不知道是什么中断请求…

记一次 .NET 某电子厂OA系统 非托管内存泄露分析

一&#xff1a;背景 1.讲故事 这周有个朋友找到我&#xff0c;说他的程序出现了内存缓慢增长&#xff0c;没有回头的趋势&#xff0c;让我帮忙看下到底怎么回事&#xff0c;据朋友说这个问题已经困扰他快一周了&#xff0c;还是没能找到最终的问题&#xff0c;看样子这个问题…

hyper-v 虚拟机与本机之间 sftp实现文件传输

hyper-v 主打安全性&#xff0c;所以跟VMware不一样&#xff0c;不能实现复制粘贴&#xff1a;文字、文件、文件夹&#xff0c;所以采取了折中的办法&#xff0c;在Windows主机端用power shell&#xff0c;sftp命令进行文件传输。 前提 需要安装并能够正常运行ssh&#xff0c;后…

C++实现彩色bmp图片转灰度图

简介 BMP&#xff08;全称Bitmap&#xff09;是Windows操作系统中的标准图像文件格式&#xff0c;可以分成两类&#xff1a;设备相关位图&#xff08;DDB&#xff09;和设备无关位图&#xff08;DIB&#xff09;&#xff0c;使用非常广。它采用位映射存储格式&#xff0c;除了…

第05章_存储引擎

第05章_存储引擎1. 查看存储引擎2. 设置系统默认的存储引擎3. 设置表的存储引擎3.1 创建表时指定存储引擎3.2 修改表的存储引擎4. 引擎介绍4.1 InnoDB 引擎:具备外键支持功能的事务存储引擎4.2 MyISAM 引擎:主要的非事务处理存储引擎4.3 Archive 引擎:用于数据存档4.4 Blackhol…

认真过一遍webpack

1. 简介 Webpack 是 前端资源打包工具&#xff0c;它会根据模块之间的依赖关系进行静态分析&#xff0c;将模块按照指定的规则生成对应的静态资源。 webpack会从入口文件开始打包&#xff0c;先形成依赖关系图&#xff0c;根据依赖图把不同的资源引进来形成一个chunk代码块&a…

Flutter 这个评分组件用起来真香

前言 在很多应用中,我们都需要收集用户的评分,比如商品满意度、配送满意度、应用使用体验等等。评分组件通常会是下面这样,一般满分是5分。 不过,有时候评分组件也会有一些特殊性(都怪产品的想法太多)。比如要求支持0.5分的评分,比如对不同的满意度使用不同的图标,再…

vscode - vscode中使用svn插件进行提交代码

本文介绍工作中在vscode上使用svn插件进行提交代码&#xff1b; 前提&#xff1a;自己需要安装svn服务端和客户端&#xff08;小乌龟&#xff09; svn服务端链接&#xff1a;https://www.visualsvn.com/server/download/ svn客户端链接&#xff1a;https://tortoisesvn.net/dow…

守护安全|AIRIOT城市天然气综合管理解决方案

城市使用天然气存在安全风险和隐患&#xff0c;天然气管理的复杂性也比较高&#xff0c;依靠传统人工难以发现安全漏洞&#xff0c;特别是在燃气场站、管网的安全监管等方面&#xff0c;场站面临作业管理、区域管控等问题&#xff0c;管线存在第三方施工发现问题不及时、监管难…

Java实战-用Java mail实现Exchange发邮件给你喜欢的人

目录1. 官方指导文章2. 需要用到com.microsoft.ews-java-api2.1 maven中添加2.2 gradle中添加3. 完整代码&#xff1a;新建一个MailUtil.java类&#xff1a;如何用java mail 实现Exchange发邮件的功能 1. 官方指导文章 官方文章&#xff1a;https://github.com/OfficeDev/ews…

设计模式(下)

四、行为型模式 4.1 模板方法模式 4.1.1 概述 在面向对象程序设计过程中&#xff0c;程序员常常会遇到这种情况&#xff1a;设计一个系统时知道了算法所需的关键步骤&#xff0c;而且确定了这些步骤的执行顺序&#xff0c;但某些步骤的具体实现还未知&#xff0c;或者说某些…

swin Transformer

文章目录swin Transformer创新点&#xff1a;网络架构&#xff1a;Patch Partitionlinear EmbeddingSwin TransformerPatch Merging总结swin Transformer 论文&#xff1a;https://arxiv.org/pdf/2103.14030.pdf 代码&#xff1a;https://github.com/microsoft/Swin-Transfor…

基于FDB方法的供给需求优化算法改进——基于工程设计问题的综合研究

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

校园网页设计成品 学校班级网页制作模板 dreamweaver网页作业 简单网页课程成品 大学生静态HTML网页源码

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

ArangoDB简单入门

一、安装与启动 1、进入到某个目录 cd /home/neunhoef/ 2 获取包 wget https://download.arangodb.com/arangodb34/Community/Linux/arangodb3-linux-3.4.1.tar.gz 3、解压 tar xzvf arangodb3-linux-3.4.1.tar.gz 4、将使用的命令放到path中 export PATH"/home/neunhoef…

Ajax学习:原生jsonp实践

输入内容&#xff1a;丧失焦点 向服务器发送请求 对用户名做是否存在的检测 并且改变框的颜色 服务端&#xff1a; const {json } require(express); const express require(express)const app express(); app.get(/home, function(requset, response) {//设置响应头 名称…