【C++】STL- > string类(超详解!!!)

news2025/1/16 20:13:49

文章目录

  • 前言
  • 1、string类的出现
    • 1.1 C语言中的字符串
    • 1.2 平时使用
  • 2. 标准库中的string类
    • 2.1 string类的常用文档(重要)!!!!
    • 2.2 string类的常用接口说明(接口原型我这里就不展示了,文档中都有可以去文档中去查找)
      • 1. string类对象的常见构造
      • 2. string类对象的容量操作
      • 3. string类对象的访问及遍历操作
      • 4. string类对象的修改操作
      • 5. string类非成员函数
    • 2.3 关于string的练习题
  • 3. string类的模拟实现
    • 3.1 经典的string类问题
    • 3.2 浅拷贝
    • 3.3 深拷贝
      • 3.3.1 传统版写法的string类
      • 3.3.2 现代版写法的string类
    • 3.3 写时拷贝(了解)
    • 3.4 string类的模拟实现
  • 总结
  • 参考资料(都是一些很好的文章和文档搜索网站)


前言

提示:这里可以添加本文要记录的大概内容:

字符串是编程中非常重要的数据类型,用于存储和处理文本信息。在C++中,可以使用两种主要方式来表示和操作字符串:

  • C风格字符串:以空字符(‘\0’)结尾的字符数组,例如"Hello, world!"。这种方式比较传统,但存在一些缺点,例如不易于使用和不安全。
  • string类:C++标准模板库(STL)中提供的类,专门用于表示和操作字符串。它具有易于使用、安全等优点。
    本文将介绍C++ STL中的string类,包括其基本概念、使用方法、模拟实现以及扩展阅读等内容。

提示:以下是本篇文章正文内容,下面案例可供参考

1、string类的出现

1.1 C语言中的字符串

C语言中,字符串是以’\0’结尾的一些字符的集合,为了操作方便,C标准库中提供了一些string系列的库函数, 但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可 能还会越界访问。

1.2 平时使用

在平时使用中,不管是学习还是工作都需要大量用到string,很少有人会用C库中的库函数去操作字符串,string类的出现不仅仅是为了弥补C语言的缺陷,也是为了让我们快速操作字符串

2. 标准库中的string类

2.1 string类的常用文档(重要)!!!!

在库中,甚至是string中的接口都是数量很大的,如果要求我们每一个接口都十分熟悉那显示是不可能的,那么就需要我们学习利用文档学习,下面给出一个常用文档

如果觉得页面卡顿或者是用着不习惯,也可能使用以前的旧版本,更加的简洁(标红处)
在这里插入图片描述

注意:在使用string类时,必须包含#include头文件以及using namespace std;

2.2 string类的常用接口说明(接口原型我这里就不展示了,文档中都有可以去文档中去查找)

1. string类对象的常见构造

在这里插入图片描述
主要考虑以下几个接口
在这里插入图片描述

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string s1;//构造空的string类对象,即空字符串
	string s2("hello cplusplus!!!");//用C-string来构造string类对象
	string s3(s2);//拷贝构造函数
	cout << s1 << endl;
	cout << s2 << endl;
	cout << s3 << endl;
	return 0;
}

2. string类对象的容量操作

在这里插入图片描述

void testString2()
{
	string s1("hello cplusplus!!");
	size_t n = s1.size();
	cout << n << endl;
	cout << s1.capacity() << endl;
	cout << s1.empty() << endl;
	s1.clear();//清空字符串中的内容,使其成为空字符串,但是不会改变size的值和容量的值
	n = s1.size();
	cout << n << endl;
	cout << s1.capacity() << endl;
	cout << s1.empty() << endl;
	s1.reserve(100);//reserve在英文中的意思是预定的意思,相当于预定了你指定空间的容量
	n = s1.size();
	cout << n << endl;
	cout << s1.capacity() << endl;
	cout << s1.empty() << endl;
	s1.resize(20,'a');
	n = s1.size();
	cout << n << endl;
	cout << s1.capacity() << endl;
	cout << s1.empty() << endl;
}

注意:

  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 n = 0):为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserve不会改变容量大小。

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

这里的迭代器大家目前可以暂时理解为指针
在这里插入图片描述
上述图片的表述有一些错误,rbegin和rend和begin、end相反,他们是反着打印,获取的也是相反的(具体可以去之前提到的文档链接去查到内容即可)

void testString3()
{
	string s1("hello cplusplus!!");
	const string s2("hello cplusplus!!");
	cout << s1 << " " << s2 << endl;
	cout << s1[0] << " " << s2[0] << endl;
	s1[0] = 'a';
	//s2[0] = 'a';//这里会发生编译错误,因为const类型对象不能修改
	cout << s1<<endl;



	string s("hello,c++");
	//三种遍历方式:
	//需要注意的是,以下三种方式除了遍历打印string对象,还可以适用于遍历修改string中的字符
	//另外,三种方式中,对于string而言,第一种方式使用的最多

	// 1. for+operator[]
		for(size_t i = 0; i < s.size(); i++)
		{
			cout << s[i]<<" ";
		}
		cout << endl;
	// 2.迭代器(这种方式底层大家暂时先不用明白,先了解大概怎么用,了解用法)
		//string::iterator it = s.begin();
		auto it = s.begin();

		while (it != s.end())
		{
			cout << *it << " ";
			it++;
		}
		cout << endl;
	// 3.范围for
		for (auto& ch : s)
		{
			cout << ch << " ";
		}

}

4. string类对象的修改操作

在这里插入图片描述

void testString4()
{
	string s1("hello_c++");
	string s2("-hhh");
	s1.push_back('a');
	cout << s1 << endl;
	s1.append(s2);
	cout << s1 << endl;
	s1.append("xxx");
	cout << s1 << endl;
	s1 += '\0';
	s1 += "111";
	cout << s1 << endl;
	const char* s = s1.c_str();
	cout << s << endl;
	size_t n = s1.find("111",1);
	cout << n << endl;
	 n = s1.rfind("hhh",18 );
	cout << n << endl;
	string s3 = s1.substr(0, 3);
	cout << s3 << endl;
}

注意:

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

5. string类非成员函数

在这里插入图片描述

**void testString5()
{
	string s1("hello_cpp");
	string s3 = s1.substr(0, 3);
	cout << s3 << endl;
	s1 = s1 + s3;
	cout << s1 << endl;
	string s2;
	//operator>>(cin,s2);
	//cout << s2 <<endl;
	getline(cin,s2);
	cout << s2 << endl;
	cout << ("abc" > "bbb") << endl;
}
**

上面的几个接口大家了解一下,下面的OJ题目中会有一些体现他们的使用。string类中还有一些其他的
操作,这里不一一列举,大家在需要用到时不明白了查文档即可。

2.3 关于string的练习题

  1. 题目一
  2. 题目二
  3. 题目三
  4. 题目四
  5. 题目五
  6. 题目六
  7. 题目七
  8. 题目八
  9. 题目九
  10. 题目十
  11. 题目十一

3. string类的模拟实现

3.1 经典的string类问题

上面已经对string类进行了简单的介绍,大家只要能够正常使用即可。在面试中,面试官总喜欢让学生自己
来模拟实现string类,最主要是实现string类的构造、拷贝构造、赋值运算符重载以及析构函数。大家看下以
下string类的实现是否有问题?

class string
{
public:
 /*string()
 :_str(new char[1])
 {*_str = '\0';}
 */
 //string(const char* str = "\0") 错误示范
 //string(const char* str = nullptr) 错误示范
 string(const char* str = "")
 {
 // 构造string类对象时,如果传递nullptr指针,认为程序非法,此处断言下
 if(nullptr == str)
 {
	 assert(false);
	 return;
 }
 
	 _str = new char[strlen(str) + 1];
	 strcpy(_str, str);
 }
 
 ~string()
 {
 if(_str)
 {
	 delete[] _str;
	 _str = nullptr;
 }
 }
 
private:
	 char* _str;
};
// 测试
void Teststring()
{
 	string s1("hello bit!!!");
 	string s2(s1);
}

在这里插入图片描述
说明:上述string类没有显式定义其拷贝构造函数与赋值运算符重载,此时编译器会合成默认的,当用s1构
造s2时,编译器会调用默认的拷贝构造。最终导致的问题是,s1、s2共用同一块内存空间,在释放时同一块
空间被释放多次而引起程序崩溃,这种拷贝方式,称为浅拷贝。

3.2 浅拷贝

浅拷贝:也称值拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致多个对象共
享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为
还有效,所以 当继续对资源进项操作时,就会发生发生了访问违规。要解决浅拷贝问题,C++中引入了深拷
贝。

3.3 深拷贝

如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。一般情
况都是按照深拷贝方式提供。

在这里插入图片描述

3.3.1 传统版写法的string类

class string
{
public:
	string(const char* str = "")
	{
		// 构造string类对象时,如果传递nullptr指针,认为程序非法,此处断言下
		if (nullptr == str)
		{
			assert(false);
			return;
		}

		_str = new char[strlen(str) + 1];
		strcpy(_str, str);
	}

	string(const string& s)
		: _str(new char[strlen(s._str) + 1])
	{
		strcpy(_str, s._str);
	}

	string& operator=(const string& s)
	{
		if (this != &s)
		{
			char* pStr = new char[strlen(s._str) + 1];
			strcpy(pStr, s._str);
			delete[] _str;
			_str = pStr;
		}

		return *this;
	}

	~string()
	{
		if (_str)
		{
			delete[] _str;
			_str = nullptr;
		}
	}

private:
	char* _str;
};

3.3.2 现代版写法的string类

class string
{
public:
	string(const char* str = "")
	{
		if (nullptr == str)
			str = "";
		_str = new char[strlen(str) + 1];
		strcpy(_str, str);
	}

	string(const string& s)
		: _str(nullptr)
	{
		string strTmp(s._str);
		swap(_str, strTmp._str);
	}

	// 对比下和上面的赋值那个实现比较好?
	string& operator=(string s)
	{
		swap(_str, s._str);
		return *this;
	}

	/*
	string& operator=(const string& s)
	{
	if(this != &s)
	{
	string strTmp(s);
	swap(_str, strTmp._str);
	}

	return *this;
	}
	*/

	~string()
	{
		if (_str)
		{
			delete[] _str;
			_str = nullptr;
		}
	}

private:
	char* _str;
};

3.3 写时拷贝(了解)

写时拷贝就是一种拖延症,是在浅拷贝的基础之上增加了引用计数的方式来实现的。

引用计数:用来记录资源使用者的个数。在构造时,将资源的计数给成1,每增加一个对象使用该资源,就给
计数增加1,当某个对象被销毁时,先给该计数减1,然后再检查是否需要释放资源,如果计数为1,说明该
对象时资源的最后一个使用者,将该资源释放;否则就不能释放,因为还有其他对象在使用该资源。

3.4 string类的模拟实现

查看完整代码

总结

本文介绍了C++ STL中的string类的基本概念和使用方法,包括:

  • string类的创建和初始化
  • 访问和修改字符串内容
  • 常用字符串操作函数
  • 模拟实现string类
  • 扩展阅读
    通过本文的学习,读者应该能够掌握string类的基本用法,并能够在实际编程中使用它来完成各种字符串操作。

参考资料(都是一些很好的文章和文档搜索网站)

  • C++ STL string类使用及实现详解: https://blog.csdn.net/xiang_bolin/article/details/136097284
  • 【C++】深入浅出STL之string类: https://blog.csdn.net/fire_cloud_1/article/details/131914378
  • std::string class in C++: https://www.geeksforgeeks.org/stdstring-class-in-c/
  • https://cplusplus.com/reference/string/string/

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

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

相关文章

springcloud-远程调用

微服务的远程调用 RestTemplate 在项目中&#xff0c;当我们需要远程调用一个 HTTP 接口时&#xff0c;我们经常会用到 RestTemplate 这个类。这个类是 Spring 框架提供的一个工具类。 实例化RestTemplate 创建配置类&#xff0c;实例化RestTemplate Configuration public clas…

ubuntu解决“E: Unable to locate package lrzsz“

今天在ubuntu上安装rzsz包时报错&#xff0c;提示无法定位包&#xff0c;提示如下 出现这个问题是因为apt的源没有更新&#xff0c;我们直接说解决办法 把下面的命令执行一遍即可 sudo add-apt-repository main sudo add-apt-repository universe sudo add-apt-repository re…

【漏洞复现】H3C 路由器多系列信息泄露漏洞

Nx01 产品简介 H3C路由器是一款高性能的路由器产品&#xff0c;具有稳定的性能和丰富的功能。它采用了先进的路由技术和安全机制&#xff0c;可以满足不同用户的需求&#xff0c;广泛应用于企业、运营商和数据中心等领域。 Nx02 漏洞描述 H3C路由器多系列存在信息泄露漏洞&…

“薪”的一年程序员裁员潮技术变革情况下 程序员就业机会在哪里?

引言&#xff1a;一对来自中国的工程师夫妻在美国的不幸身亡&#xff0c;疑似与谷歌的裁员有关&#xff0c;这一事件再次引发了人们对技术变革下裁员对程序员影响的关注。 一、针对裁员潮的一些看法 在我看来&#xff0c;技术变革对程序员的影响是双面的。一方面&#xff0c;…

抛弃chatgpt,使用微软的Cursor提升coding效率

Whats Cursor? Cursor编辑器是一个基于GPT-4的代码编辑器&#xff0c;它可以根据用户的自然语言指令或者正在编辑的代码上下文为用户提供代码建议&#xff0c;支持多种编程语言&#xff0c;如Python、Java、C/C#、go等。Cursor编辑器还可以帮助用户重构、理解和优化代码&…

管式土壤墒情监测仪

TH-GTS04随着农业技术的不断进步&#xff0c;土壤墒情监测在农业生产中的作用越来越突出。管式土壤墒情监测仪作为一种先进的土壤水分测量工具&#xff0c;为农业生产提供了准确、实时的土壤水分数据&#xff0c;为科学决策提供了有力支持。 一、管式土壤墒情监测仪的工作原理…

【力扣 - 二叉树的最大深度】

题目描述 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 提示&#xff1a; 树中节点的数量在 [0, 10^4] 区间内。 -100 < Node.val < 100方法一&#xff1a;深度优先搜索 思路与算法 如…

Redis第一关之常规用法

简介 Redis不用多说&#xff0c;已经火了很多年了&#xff0c;也用了很多年了。现在做一些归纳总结。 这篇文章主要介绍Redis的常规知识及用法&#xff0c;包括数据结构、使用场景、特性、过期机制、持久化机制。 Redis与Mysql Mysql是一款基于磁盘的关系型SQL数据库。 Redi…

软件实际应用实例分享,门诊电子处方模板制作教程,中西医诊所病历开单系统教程

软件实际应用实例分享&#xff0c;门诊电子处方模板制作教程&#xff0c;中西医诊所病历开单系统教程 一、前言 以下软件教程以 佳易王诊所电子处方软件V17.3为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 1、在开电子处方的时候&#xff0c…

RocketMQ(五):功能特性——消费管理

1 消费者负载均衡 消费者从Apache RocketMQ获取消息消费时&#xff0c;通过消费者负载均衡策略&#xff0c;可以将主题内的消息分配给指定消费者分组中的多个消费者共同分担&#xff0c;提高消费并发能力和消费者的水平扩展能力。 1.1 背景信息 了解消费者负载均衡策略&#x…

文献学习-1-Continuum Robots for Medical Interventions

Chapt 5. 连续体机构分析 5.1 文献学习 5.1.1 Continuum Robots for Medical Interventions Authors: PIERRE E. DUPONT , Fellow IEEE, NABIL SIMAAN , Fellow IEEE, HOWIE CHOSET , Fellow IEEE, AND CALEB RUCKER , Member IEEE 连续体机器人在医学上得到了广泛的应用&a…

“比特币突破5.2万美元”,一枚币可换一斤半黄金?黄金比特币之争再次甚嚣尘上!

自今年1月美国SEC批准比特币现货ETF登陆美股市场之后&#xff0c;只用了短短的30个交易日&#xff0c;比特币ETF就从零膨胀到了近400亿美元的规模&#xff0c;超过白银ETF约100多亿美元的规模&#xff0c;和规模约为900多亿美元的黄金ETF暂时形成了“三七开”的格局。比特币现货…

SpringBoot自动注入源码分析

Spring Boot何时注入Autowired标注的属性&#xff1f; 是在Bean实例化后&#xff0c;填充Bean的时候注入Autowired标注的属性 如果注入类型的Bean存在多个&#xff0c;Spring Boot是如何处理的&#xff1f; 如果存在多个类型的Bean&#xff0c;会根据primary—>javax.ann…

电脑屏幕录制工具 Top10 榜单,免费无水印方法集

随着媒体行业的突飞猛进&#xff0c;不同服务之间对有效屏幕录制的竞争日益激烈。这导致市场上出现了质量参差不齐的屏幕录像机。特别是有些录屏器会自动给你录制的视频加上水印&#xff0c;给需要在公共场合使用的人留下不专业的印象。除此之外&#xff0c;它们甚至不能保护您…

【postgresql】ERROR: relation “data_screen.import_record_id_seq“ does not exist

创建表时候提示下面错误&#xff1a; ERROR: relation "data_screen.import_record_id_seq" does not exist 错误&#xff1a;关系“data_screen.import_record_id_seq”不存在 创建语句 CREATE TABLE "data_screen"."import_record" ("…

[框架系列]-[通用lock框架]

通用lock框架 项目特点一:框架集成1.引入核心依赖2.使用redis厂商lock默认实现Redisson3.使用zookeeper厂商lock 二:api调用示例三:注解支持1.注解介绍2.注解使用示例 四:lock增强五:全局锁降级六:配置1.配置清单2.具体配置介绍3.配置demo 七:CUSTOMER的SPI扩展示例1.SPI扩展点…

人工智能实训室解决方案2024

人工智能实训室解决方案 一、专业背景 人工智能是一门新兴的技术科学&#xff0c;旨在模拟、延伸和扩展人的智能。它涉及多个领域&#xff0c;如机器人、语言识别、图像识别、自然语言处理和专家系统等。人工智能的实际应用广泛&#xff0c;包括机器视觉、指纹识别、人脸识别…

谈谈:你在工作中用到的设计模式!

谈谈:你在工作中用到的设计模式! Hello大家龙年好! 春节的假期转眼间过去,我们也要回归往日的节奏 因为最近和小伙伴们聊天发现,我们普遍在面试中,对被问起设计模式在工作中的应用,既有点熟悉,又有点陌生, 在网上看吧,又感觉鸡肋(为啥?不能解燃煤之急啊!哈哈),所以,为了打破这…

【STC8A8K64D4开发板】第2-12讲:数码管显示

第2-12讲&#xff1a;数码管显示 学习目的了解数码管分类、工作原理及驱动电路的设计。掌握STC8A8K64D4系列单片机驱动8位共阴数码管的动态显示的软件设计。 数码管概述 数码管是一种常用的显示设备&#xff0c;他有着价格便宜、使用简单的特点&#xff0c;在各个领域被广泛的…

学生用台灯多少瓦比较合适呢?五大优质护眼台灯无广实测推荐

护眼台灯的出现成为众多宝妈人群青睐的对象&#xff0c;都希望能借助它的力量来保护孩子的视力健康。这类台灯不仅拥有柔和而舒适的光线&#xff0c;而且能有效防蓝光和眩光&#xff0c;提供恰到好处的色温&#xff0c;为孩子们创造一个理想的学习环境。然而&#xff0c;市面上…