C++学习指南(四)------string

news2024/12/25 9:14:57

欢迎来到繁星的CSDN。本期内容主要包括字符串string。

一、什么是string?

      C语言中的string

   我们在C语言中已经遇到过字符串了。

   那为什么C++还要单独的列出来string呢?

 

   尽管这里包的头文件是iostream,但arr数组储存常量字符串123456789的形式仍然是C语言中的,即将字符串中的每个字符储存在一个对应数组元素中,以便可以一个个访问。

   但是麻烦的是,在书写某些代码的时候,我们需要注意\0是否被覆盖。

   不然“烫烫烫烫”警告。

   除此以外,大部分的功能还需要我们自己实现,这大大下降了我们开发的效率。所以我们对string,特别封装了一个类,而这也是打开STL库的序章(尽管string不在这其中)

二、string的功能/函数

        string功能多多,基本将开发的所有情况都统概了一遍,但是由于封装时间较早,所以在说明文档里的函数和功能较多。

        而且存在重复的情况(如length和size功能完全相同,+=和append功能完全相同等等)

        所以在此罗列一些函数说明,而要想看所有功能也可以到以下链接查看。

        cplusplus.com/reference/

        (只需要在左侧点到string部分即可查看)

        特别注释:

        以下演示的函数参数,仅仅是为了表示参数类型和功能,实际应用时还请查看文档。

      2.1string的构造函数

        作为一个类,自然少不了构造,而主要的构造方式有以下几种。

   string();                                        //构造一个空string。

   string(const char*s);                    //根据C语言格式的字符串构造一个string。

   string(size_t n,char c);                 //在该string中构造n个字符,字符为给出的c。

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

      2.2string的容量操作

        我们时常关心某一字符串的长度,并且有了strlen函数。

        在顺序表中,我们还特地写了一个size,一个capacity。

        但现在对于字符串而言,我们有了更简便的方式。

   size();                                   //返回字符串有效字符长度    

   capacity();                            //返回空间总大小

   empty();                               //检测字符串是否为空

   clear();                                 //清空字符串

   reserve(size_t n);                //为字符串预留空间

   resize(size_t n,char c);       //将有效字符的个数改为n个,多出的空间用字符填充

   注:

   size和length的底层一致,功能相同,并且按照vector等其他容器的惯常用法,只需记size

   clear函数只会清空字符串,而不改变capacity,即开辟空间的大小。

   reserve函数在不同编译器中表现不同,不同点在于如果n开的过大,VS2022不会进行缩容操作,但g++(即linux)环境下会进行缩容操作。而在说明文档中,我们注意到non-binding一词,所以这两种操作都是被允许的。使用不同编译器的时候,需要注意。

       2.3string的访问

         对于开辟的字符串,我们自然也需要方便的访问方式。

        与C语言中一样,我们特地重载了[ ] ,作为访问string的方式。

   operator[ ]     //返回pos位置的字符,const string类对象调用。

   begin()          //begin获取一个字符的迭代器,可以暂时理解为类似于数组首元素指针。

                          但实际上并不相同。

   end()             //end获取最后一个字符下一个位置的迭代器。

   rbegin()         //rbegin获取一个字符的反向迭代器,即从字符串的末尾开始。

   rend()            //rend获取最后一个字符下一个位置的反向迭代器。

        其中,begin与end代表了正向迭代器,rbegin与rend代表了反向迭代器。

        这两对迭代器为我们提供了正向与反向的遍历方式,但需要注意的是:只需要迭代器++(已重载),即可实现遍历,无需费心是++还是--了。

string v;
std::iterator it=v.begin();//iterator即迭代器
for(;it<v.end();it++){
// write code here
}

        我们以后还会再次遇见迭代器,而且会更加频繁,更加底层的理解。

        还有一种访问方式,范围for访问,是在C++11才出现的新遍历方式。

string v("Hello world");
for(int i=0;i<v.size();i++){
    //C++98风格
}

for(char ch:v){
    //C++11风格
}

        如此访问有一个好处,就是不必再担心什么时候加加,冒号前的ch即在字符串中读到的每个字符。但缺点在于,如果用范围for,我们就不能再跳着访问了,只能从头到尾全部一个一个访问。

        值得庆幸的是,两种访问都可以使用,所以我们只需要挑更简便更熟悉的搭配使用即可。

      2.4string的修改操作

        访问对应的修改必不可少。

   push_back(char c);                                //尾插一个字符c   

   append(string str);                                 //尾插一个字符串(有大量重载函数)

   operator+=(string str);                           //尾插一个字符串,和append功能相同

   c_str();                                                   //返回一个C语言格式的字符串,即数组储存形式   

   find(char c);                                           //从字符串起始开始寻找字符c,找到即返回位置,                                                                     未找到,返回npos,即-1。

   rfind(char c);                                          //反向寻找字符串中的字符c,找到即返回位置,未                                                                     找到返回npos,即-1。

   substr(size_t pos , size_t len)                //从pos位置开始截取长度为len的字符串。

      2.5string的非成员函数

   operator+                                        //返回一个叠加后的字符串,但尽量少用

   operator>>                                      //输入运算符重载

   operator<<                                      //输出运算符重载

   getline                                             //获取一行字符串,只有遇到换行才会停止,可以用于                                                               接受带空格的字符串

   relational operators                         //字符串大小比较(包含==,!=,<=,>=,<,>)

        这几个函数都比较好用,起到了替代手动书写的作用。

三、string的模拟实现

        如果我们能从底层源码剖析,那么就可以更好地理解string。

        于是我斗胆写了一份string的模拟实现(请务必不要当作真正源码来看待),供参考。

        

namespace show {
	const size_t string::npos = -1;
	class string {
	public:
		typedef char* iterator;
		string(const char* str = "") {
			_size = strlen(str);
			_capacity = _size;
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}
		string(const string& s) {
			_size = s._size;
			_capacity = s._capacity;
			_str = new char[_capacity + 1];
			strcpy(_str, s._str);
		}
		void swap(string& s) {
			std::swap(_size, s._size);
			std::swap(_capacity,s._capacity);
			std::swap(_str , s._str);
		}
		string& operator=(const string& s) {
			if (_str != s._str) {
				delete[] _str;
				_size = s._size;
				_capacity = s._capacity;
				_str = new char[_capacity + 1];
				strcpy(_str, s._str);
			}
			return *this;
		}
		~string() {
			if (_str) {
				delete[] _str;
				_str = nullptr;
				_size = _capacity = 0;
			}
		}
		iterator begin() {
			return _str;
		}
		iterator end() {
			return _str + _size;
		}
		void reserve(size_t n) {
			if (n > _capacity) {
				char* tmp = new char[n + 1];
				strcpy(tmp, _str);
				delete[]_str;
				_str = tmp;
				_capacity = n;
			}
		}
		void push_back(char c) {
			if (_size == _capacity) {
				reserve(_capacity == 0 ? 4 : _capacity * 2);
			}
			_str[_size++] = c;
			_str[_size] = '\0';
		}

		string& operator+=(char c) {
			push_back(c);
			return*this;
		}

		void append(const char* str) {
			size_t len = strlen(str);
			if (_size + len > _capacity) {
				reserve(_size + len > 2 * _capacity ? _size + len : 2 * _capacity);
			}
			strcpy(_str + _size, str);
			_size=_size + len;
		}

		string& operator+=(const char* str) {
			append(str);
			return*this;
		}

		void clear() {
			_size = 0;
			_str[0] = '\0';
		}
		const char* c_str()const {
			return _str;
		}
		size_t size()const{
			return _size;
		}

		size_t capacity()const{
			return _capacity;
		}

		bool empty()const{
			return _size == 0;
		}

		void resize(size_t n, char c = '\0') {
			if (n > _capacity) {
				reserve(n);
				for (int i = _size; i < n; i++) {
					_str[i] = c;
				}
			}
			else {
				_size = n;
			}
		}
		char& operator[](size_t index) {
			assert(index < _size);
			return _str[index];
		}

		const char& operator[](size_t index)const {
			assert(index < _size);
			return _str[index];
		}

		bool operator<(const string& s) {
			return strcmp(c_str(), s.c_str()) < 0;
		}

		bool operator<=(const string& s) {
			return *this < s || *this == s;
		}

		bool operator>(const string& s) {
			return !(*this <= s);
		}

		bool operator>=(const string& s) {
			return !(*this < s);
		}

		bool operator==(const string& s) {
			return strcmp(c_str(), s.c_str()) == 0;
		}

		bool operator!=(const string& s) {
			return !(*this == s);
		}
		size_t find(char c, size_t pos = 0) const {
			assert(pos < _size);

			for (size_t i = pos; i < _size; i++)
			{
				if (_str[i] == c)
				{
					return i;
				}
			}

			return npos;
		}
		size_t find(const char* s, size_t pos = 0) const {
			assert(pos < _size);
			const char* ptr = strstr(_str + pos, s);
			if (ptr == nullptr)
			{
				return npos;
			}
			else
			{
				return ptr - _str;
			}
		}
		string& insert(size_t pos, char c) {
			assert(pos <= _size);

			if (_size == _capacity)
			{
				reserve(_capacity == 0 ? 4 : _capacity * 2);
			}

			// 挪动数据
			size_t end = _size + 1;
			while (end > pos)
			{
				_str[end] = _str[end - 1];
				--end;
			}

			_str[pos] = c;
			++_size;
		}

		string& insert(size_t pos, const char* str) {
			assert(pos <= _size);

			size_t len = strlen(str);
			if (_size + len > _capacity)
			{
				// 大于2倍,需要多少开多少,小于2倍按2倍扩
				reserve(_size + len > 2 * _capacity ? _size + len : 2 * _capacity);
			}

			size_t end = _size + len;
			while (end > pos + len - 1)
			{
				_str[end] = _str[end - len];
				--end;
			}

			for (size_t i = 0; i < len; i++)
			{
				_str[pos + i] = str[i];
			}

			_size += len;
		}
		string& erase(size_t pos, size_t len) {
			assert(pos < _size);

			if (len >= _size - pos)
			{
				_str[pos] = '\0';
				_size = pos;
			}
			else
			{
				for (size_t i = pos + len; i <= _size; i++)
				{
					_str[i - len] = _str[i];
				}

				_size -= len;
			}
		}
	private:
		char* _str = nullptr;
		size_t _size = 0;
		size_t _capacity = 0;
		static const size_t npos = -1;
	};
}

        

        本篇内容到此结束,谢谢大家的观看!

        觉得写的还不错的可以点点关注,收藏和赞,一键三连。

        我们下期再见~

        往期栏目:  

        C++学习指南(一)——C++入门基础-CSDN博客

        C++学习指南(二)——类和对象-CSDN博客

        C++学习指南(三)——模板_模板显示实例化-CSDN博客

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

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

相关文章

Leetcode - 周赛410

目录 一&#xff0c;3248. 矩阵中的蛇 二&#xff0c;3249. 统计好节点的数目 三&#xff0c;3250. 单调数组对的数目 I dfs记忆化 dfs记忆化1&#xff1a;1改递推 四&#xff0c;3251. 单调数组对的数目 II 一&#xff0c;3248. 矩阵中的蛇 本题就是一道纯模拟题&#x…

JavaScript Web API入门day3

目录 1.事件流 1.1 事件流和两个阶段说明 1.2 事件捕获 1.3 事件冒泡 1.4 阻止冒泡 1.5 解除默认行为 1.6 解绑事件 2.事件委托 3.其他事件 3.1 页面加载事件 3.1.1 load方式 3.1.2 DOMContentLoaded 3.2 元素滚动事件 3.2.1 什么是元素滚动事件 3.2.2 获取元素…

【qt小系统】通过qt折线图实现论文内容-快餐店排队效能分析

摘要&#xff1a; 商户收银需求与收银能力不匹配&#xff0c;是一个普遍问题&#xff0c;高峰不足/平常过剩。参考论文《混合制排队模型下中式快餐店排队系统的优化_荣艳蕊.pdf》&#xff0c;本文主要使用QT5、QtChart等完成了基于以上论文模型的关于排队模型优化的图表对比功能…

精品UI资源下载分享类响应式模板素材资源下载站源码

在其他网站看到的这个源码&#xff0c;感觉UI挺漂亮的&#xff0c;就搬来了。 感兴趣的自己下载后搭建下看看&#xff0c;个人感觉UI很漂亮 2024/8/10修复&#xff1a; 标签页面显示的文章跳转链接不正确 源码下载&#xff1a;https://download.csdn.net/download/m0_66047…

开源免费的表单收集系统TDuck

TDuck&#xff08;填鸭表单&#xff09;是一款开源免费的表单收集系统&#xff0c;它基于Apache 2.0协议开源&#xff0c;用户可以随时下载源码&#xff0c;自由修改和定制&#xff0c;也可以参与到项目的贡献和反馈中。TDuck表单系统不仅支持私有化部署&#xff0c;还提供了丰…

uniapp预览图片uni.previewImage图片放大

<image v-if"file.image!" :src"file.image" click"previewImage(file.image)"></image>file: {image: ,status: 1}, // 预览 图片previewImage() {uni.previewImage({current: 1,urls: [this.img] // 是个 数组 单张的&#xff08…

【产品那些事】什么是应用程序安全态势管理(ASPM)?

文章目录 前言当前应用安全(AppSec)推进遇到的问题关于ASPM的定义 为什么需要ASPM&#xff1a;B端客户核心需求ASPM产品关键策略理想状态下的ASPMASPM与CSPM的区别国内外产品参考 前言 随着现代软件开发实践的快速演变&#xff0c;特别是在敏捷开发和 DevOps 的推动下&#xf…

与人工智能相比,人类智能里包含有信仰

信仰是人类智能的一个重要方面&#xff0c;它影响我们的意图、动机、决策和行为。 人类智能中信仰是一种独特的因素&#xff0c;影响我们如何看待世界、做决定以及形成价值观。与此相比&#xff0c;人工智能虽然可以处理大量数据并模拟决策过程&#xff0c;但它不具备信仰、情感…

哈尔滨等保测评的政策解读与最佳实践分享

哈尔滨&#xff0c;这座北方城市&#xff0c;在数字化转型的浪潮中&#xff0c;对网络安全的重视程度日益提升。其中&#xff0c;等保测评&#xff08;等级保护测评&#xff09;作为信息安全领域的基石政策&#xff0c;正引领企业构建坚不可摧的安全防线。今天&#xff0c;就让…

[Qt][对话框][下]详细讲解

目录 1.Qt内置对话框0.有哪些1.消息对话框 QMessageBox2.颜色对话框 QColorDialog3.⽂件对话框 QFileDialog4.字体对话框 QFontDialog5.输⼊对话框 QInputDialog6.进度条对话框 QProgressDialog 1.Qt内置对话框 0.有哪些 Qt提供了多种可复⽤的对话框类型&#xff0c;即Qt标准…

媒体邀约新闻稿宣发的意义和作用?

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 媒体邀约新闻稿的宣发对于企业活动来说具有重要的意义和作用。这不仅能够提升企业的知名度和形象&#xff0c;还能扩大活动的影响力&#xff0c;增加媒体报道的机会&#xff0c;并建立积…

【基础解读】神奇宝贝多分类——Classification:Probabilistic Generative Model

背景 问题定义 尝试用Regression的方法解决Classification 尝试用概率的方式解决Classification 求一个个体被选中并来自于某一类的概率——贝叶斯 进行Classification 结果分析 模型调整——共用convariance matrix 结果分析 总结

Unity动画模块 之 简单创建一个序列帧动画

本文仅作笔记学习和分享&#xff0c;不用做任何商业用途 本文包括但不限于unity官方手册&#xff0c;unity唐老狮等教程知识&#xff0c;如有不足还请斧正​ 1.什么是序列帧动画 序列帧动画简单来讲就是通过连续播放一系列静态图像&#xff0c;形成动态视觉效果的过程&#xff…

Godot《躲避小兵》实战之设置项目

通过之前的学习我们已经基本了解了godot的界面&#xff0c;知道如何创建项目以及节点。那么&#xff0c;从这一章节我们将进入godot官方给我们提供的一个2D游戏开发的小教程进行入手&#xff0c;这个游戏并不是我自己的作品&#xff0c;而是我通过学习完之后&#xff0c;对其进…

Linux-软件管理

文章目录 19. 软件管理19.1 linux软件介绍19.2 RPM包概述19.3 RPM软件包安装19.4 RPM软件包依赖问题19.5 DPKG软件包19.6 linux 软件包前端工具19.7 windows 前端工具winget19.8 linux 前端工具yum概述19.9 设置yum远程仓库19.10 yum 软件包管理19.11 epel软件仓库19.12 yum本地…

机器学习中的距离概念

距离在机器学习中应用广泛&#xff0c;包括欧式距离、曼哈顿距离、内积距离和KL距离。 下面总结一下。 机器学习中的距离 欧式距离曼哈顿距离内积距离KL距离距离作为损失函数(MSE/MAE...)欧式距离与内积距离的联系☆距离的有效性 欧式距离 欧式距离&#xff08;Euclidean Dis…

数学建模——评价决策类算法Python版(灰色关联分析、主成分分析)

一、灰色关联分析 模型原理 解题步骤 例题 某公司考虑在几个候选城市中开设新的零售店。公司收集了以下数据&#xff0c;包括候选城市的GDP、人口、交通便利程度、商业发展水平等指标。公司希望使用灰色关联分析法来评估这些指标与零售店成功可能性之间的关系&#xff0c;以…

sql注入绕过+rce

目录 1、mysql编码绕过 1.1、环境搭建 1.1.1、源码 1.1.2、数据库 1.1.3、检测环境 1.2、绕过技巧 1.2.1、直接使用admin&#xff0c;查询数据&#xff0c;发现权限被拒绝 1.2.2、加上单引号绕过了&#xff0c;但是查询不到数据 1.2.3、试试其他特殊字符&#xff0c;发…

python循环——九九乘法表(更加轻松的理解循环结构)

感受 首先&#xff0c;得明确意识到这个问题&#xff0c;就是我的循环结构学的一塌糊涂&#xff0c;完全不能很好的使用这个循环来实现各种九九乘法表达输出&#xff0c;这样的循环结构太差了&#xff0c;还需要我自己找时间来补充一下循环的使用&#xff0c;来拓宽自己的思考方…

【开端】Java 分页工具类运用

一、绪论 Java系统中&#xff0c;分页查询的场景随处可见&#xff0c;本节介com.baomidou.mybatisplus.core.metadata.IPage;来分页的工具类 二、分页工具类 public class PageUtils implements Serializable { private static final long serialVersionUID 1L; /**…