STL-string的接口使用及模拟实现

news2024/11/24 1:45:00

文章目录

  • string类的介绍
  • string类的常用接口介绍
    • 构造相关
      • 无参构造
      • 字符串构造
      • 拷贝构造
    • 容量相关的接口
      • size
      • reserve
      • resize
      • capacity
      • empty
      • clear
    • 数据访问及遍历相关的接口
      • operator[]
      • begin + end
      • rbegin + rend
    • 修改数据相关的接口
      • push_back
      • operator+=
      • insert
      • erase
      • c_str
      • find + npos
      • substr
    • string相关的运算符重载
      • operator >>
      • operator <<
  • string类的模拟实现(含各类接口)

string类的介绍
string是STL标准库提供的一个处理字符串的模板类,是我们学习STL必不可少的一项。

string类的常用接口介绍

构造相关
无参构造:
在这里插入图片描述
作用:当需要一个空字符串时可以使用这个构造来实现,string s1;

字符串构造:
在这里插入图片描述
作用:可以使用常量字符串的方式来构造一个string对象,如string s2(“hello world”);

拷贝构造:
在这里插入图片描述
作用:可以用一个已经存在的string对象来进行拷贝初始化对象,如string s3(s2);

容量相关的接口
size:
在这里插入图片描述
作用:获取string对象中字符串的长度。

reserve:
在这里插入图片描述
作用:为string对象中字符串申请n个空间。

resize:
在这里插入图片描述
作用:将string对象中字符串的有效字符改为n个,如果n小于当前的size,就会截取前n个,但实际的空间容量大小不会发生改变,如果n大于当前的size,就会产生扩容,也可以指定填充字符C,指定后扩容的部分会填充为C,不指定默认是空字符。

capacity:
在这里插入图片描述
作用:返回对应string对象中字符串的空间总大小。

empty:
在这里插入图片描述
作用:检查对象中字符串是否为空串,是返回true,否则返回false。

clear:
在这里插入图片描述
作用:清空string对象中字符串的有效字符,并不会改变其空间大小。

数据访问及遍历相关的接口
operator[]:
在这里插入图片描述
作用:string类中对 [ ] 进行了重载,所以可以让我们用下标的方式来进行访问数据,并且会对数组越界进行检查,返回值是pos位置的字符的引用,可以修改,下面的是const对象使用的 [ ] ,const对象的返回值不能修改。

begin + end:
在这里插入图片描述
begin作用:获取string对象中字符串的第一个字符的迭代器
end作用:获取string对象中字符串的最后一个字符的下一个位置的迭代器
注意:
1、迭代器是STL中通用的遍历容器方式,迭代器是一种行为像指针一样的类型,但是迭代器的底层实现是不是指针不确定,具体看容器的底层实现方式,迭代器的使用方式也很像指针,迭代器++就是访问当前位置的下一个数据,- -(自减)就是前一个。
2、第二个const接口是提供给const对象调用的,普通的对象和const对象的迭代器是不一样的,不能混淆,因为const迭代器是不允许通过迭代器来修改数据的。

rbegin + rend:
在这里插入图片描述
rbegin作用:获取string对象中字符串的最后一个字符的反向迭代器
rend作用:获取string对象中字符串的第一个字符的前一个位置的反向迭代器
注意:反向迭代器是把字符串中的数据反过来进行遍历,反向迭代器的rbegin就是字符串中的尾元素,rend就是字符串中的头元素的前一个位置,对于反向迭代器++是访问当前元素的前一个,- -(自减)是访问后一个。

修改数据相关的接口
push_back:
在这里插入图片描述
作用: 在string对象的字符串中尾插一个字符c。

operator+=:
在这里插入图片描述
作用: string类中重载的一个+=运算符,可以在字符串尾部追加一个字符串,上面三个接口依次代表追加一个string对象、一个字符串、一个字符,这三个接口使用非常频繁,很重要。

insert:
在这里插入图片描述
作用:这个接口稍微复杂,可以在数组中pos位置插入字符、字符串、string对象、字符串子串,其中1-4接口是插入字符串或者string对象,5-7接口是通过pos或者迭代器位置来对字符串进行操作,其中我们只需要记住1、3、5接口常用的即可。

erase:
在这里插入图片描述
作用:对字符串进行删除字符操作。可以用pos下标的方式删除,也可以使用迭代器。

c_str:
在这里插入图片描述
作用:把当前string对象中字符串按照c格式返回。

find + npos:
在这里插入图片描述
find作用:在string对象的字符串中,从pos位置开始查找对应的字符、字符串、string对象是否存在,如果存在返回对应的起始位置,不存在返回npos。
npos作用:它是一个string类对象的公共静态成员常量,类型是size_t,npos=-1,表示size_t的最大值,通常用来表示不存在的位置。

substr:
在这里插入图片描述
作用:从字符串的pos位置开始,向后截取len个字符,并把这段字符构造成一个string对象返回。

string相关的运算符重载
operator>>:

istream& operator>>(istream& in, string& s) //流提取
	{
		s.clear();
		char ch;
		ch = in.get();
		const size_t N = 31;
		char buff[N];
		size_t i = 0;

		while (ch != ' ' && ch != '\n')
		{
			buff[i++] = ch;
			if (i == N - 1)
			{
				buff[i] = '\0';
				s += buff;
				i = 0;
			}
			ch = in.get();
		}
		buff[i] = '\0';
		s += buff;

		return in;
	}

operator<<:

	ostream& operator<<(ostream& out, const string& s) //流插入
	{
		for (size_t i = 0; i < s.size(); ++i)
		{
			out << s[i];
		}
		return out;
	}

string类的模拟实现(含各类接口)

#include <iostream>
#include <assert.h>
#include <string>
using namespace std;

namespace Lh
{
	class string
	{
	public:
		typedef char* iterator;
		typedef const char* const_iterator;
		// 普通迭代器/const迭代器
		iterator begin()
		{
			return _str;
		}
		iterator end()
		{
			return _str + _size;
		}

		const_iterator begin() const
		{
			return _str;
		}
		const_iterator end() const
		{
			return _str + _size;
		}

		//string()  //无参的构造
		//	:_str(new char[1])
		//	, _size(0)
		//	, _capacity(0)
		//{
		//	_str[0] = '\0';
		//}

        
		//string(const char* str = "\0")   //有参数的构造
		//	:_str(new char[strlen(str) + 1])
		//	, _size(strlen(str))
		//	, _capacity(strlen(str))
		//{
		//	strcpy(_str, str);
		//}
		
		string(const char* str = "")  //全缺省构造
		{
			_size = (strlen(str));
			_capacity = _size;
			_str = new char[_capacity + 1];

			strcpy(_str, str);
		}

		//string(const string& s)  //拷贝构造--传统写法
		//	:_str(new char[s._capacity+1])
		//	,_size(s._size)
		//	,_capacity(s._capacity)
		//{
		//	strcpy(_str, s._str);
		//}

		//string& operator = (const string& s) //赋值 --传统写法
		//{
		//	if (this != &s)
		//	{
		//		delete[] _str;
		//		_str = new char[s._capacity + 1];
		//		_size = s._size;
		//		_capacity = s._capacity;
		//		strcpy(_str, s._str);
		//	}
		//	return *this;
		//}
		void swap(string& tmp)
		{
			::swap(_str, tmp._str);
			::swap(_size, tmp._size);
			::swap(_capacity, tmp._capacity);
		}
		string(const string& s)  //拷贝构造--现代写法
			:_str(nullptr)
			, _size(0)
			, _capacity(0)
		{
			string tmp(s._str);
			swap(tmp);
		}

		//string& operator = (const string& s) //赋值 --现代写法
		//{
		//	if (this != &s)
		//	{
		//		string tmp(s._str);
		//		swap(tmp);
		//	}
		//	return *this;
		//}
		string& operator = (string s) //赋值 --现代写法
		{
			swap(s);
			return *this;
		}

		const char* c_str() const 
		{
			return _str;
		}

		size_t size() const  //size
		{
			return _size;
		}

		size_t capacity() const //capacity
		{
			return _capacity;
		}

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

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

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

		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 ch) //尾插
		{
			//if (_size == _capacity)
			//{
			//	reserve(_capacity == 0 ? 4 : _capacity * 2);
			//}
			//_str[_size] = ch;
			//_size++;
			//_str[_size] = '\0';

			//复用insert
			insert(_size, ch);
		}

		string& operator+=(char ch) //+=字符
		{
			push_back(ch);
			return *this;
		}
		string& operator+=(const char* str) //+=字符串
		{
			append(str);
			return *this;
		}
		string& insert(size_t pos,char ch) //任意位置插入字符
		{
			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] = ch;
			++_size;

			return *this;
		}
		string& insert(size_t pos, const char* str) //任意位置插入字符串
		{
			assert(pos <= _size);
			size_t len = strlen(str);

			//检查扩容
			if (_size + len > _capacity) 
			{
				reserve(_capacity + len);
			}

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

			return *this;
		}

		void erase(size_t pos, size_t len = npos) //某个位置删除n个字符
		{
			assert(pos < _size);
			if (len == npos || pos + len >= _size) //如果超过_size 就删除到结尾
			{
				_str[pos] = '\0';
				_size = pos;
			}
			else
			{
				strcpy(_str + pos, _str + pos + len);
				_size -= len;
			}
		}
		size_t find(char ch, size_t pos = 0) const          //查找字符
		{
			assert(pos < _size);
			for (size_t i = pos; i < _size; ++i)
			{
				if (_str[i] == ch)
				{
					return i;
				}
			}
			return npos;
		}
		size_t find(const char* sub, size_t pos = 0) const     //查找子串
		{
			assert(sub);
			assert(pos < _size);

			char* p = strstr(_str + pos, sub);
			if (p == nullptr)
			{
				return npos;
			}
			else
			{
				return p - _str;
			}
		}
		string substr(size_t pos = 0, size_t len = npos) const  //获取子串
		{
			assert(pos < _size);
			size_t realLen = len;
			if (len == npos || pos + len > _size)
			{
				realLen = _size - pos;
			}
			string sub;
			for (size_t i = 0; i < realLen; ++i)
			{
				sub += _str[pos + i];
			}
			return sub;
		}
		void resize(size_t n, char ch = '\0')
		{
			if (n > _size)
			{
				//插入数据
				reserve(n);
				for (size_t i = _size; i < n; ++i)
				{
					_str[i] = ch;
				}
				_str[n] = '\0';
				_size = n;
			}
			else
			{
				//删除数据
				_str[n] = '\0';
				_size = n;
			}
		}

		bool operator!=(const string& s) const
		{
			return !(_str == s._str);
		}
		bool operator==(const string& s) const
		{
			return strcmp(_str, s._str) == 0;
		}
		bool operator>(const string& s) const
		{
			return strcmp(_str, s._str) > 0;
		}
		bool operator>=(const string& s) const
		{
			return _str > s._str || _str == s._str;
		}
		bool operator<(const string& s) const
		{
			return !(_str >= s._str);
		}
		bool operator<=(const string& s) const
		{
			return !(_str > s._str);
		}
		void clear()
		{
			_str[0] = '\0';
			_size = 0;
		}
		~string() //析构
		{
			delete[] _str;
			_str = nullptr;
			_size = _capacity = 0;
		}
	private:
		char* _str;
		size_t _size;
		size_t _capacity;

	public:
		// const static 变量 是C++ 的语法特例 可以不在类外面定义初始化 
		// 这里就是定义初始化 光static不行 必须加const
		const static size_t npos = -1;
	};

	ostream& operator<<(ostream& out, const string& s) //流插入
	{
		for (size_t i = 0; i < s.size(); ++i)
		{
			out << s[i];
		}
		return out;
	}

	istream& operator>>(istream& in, string& s) //流提取 
	{
		s.clear();
		char ch;
		ch = in.get();
		const size_t N = 31;
		char buff[N];
		size_t i = 0;

		while (ch != ' ' && ch != '\n')
		{
			buff[i++] = ch;
			if (i == N - 1)
			{
				buff[i] = '\0';
				s += buff;
				i = 0;
			}
			ch = in.get();
		}
		buff[i] = '\0';
		s += buff;

		return in;
	}
}

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

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

相关文章

Redis搭建主从集群

搭建集群 建集群的第一件事情我们需要一些运行在 集群模式的Redis实例。这意味这集群并不是由一些普通的Redis实例组成的&#xff0c;集群模式需要通过配置启用&#xff0c;开启集群模式后的Redis实例便可以使用集群特有的命令和特性了。 下面是一个最少选项的集群的配置文件…

@Builder注解在子类中使用遇到的问题

场景 在项目开发中&#xff0c;需要基于某个类进行一些字段的拓展&#xff0c;那么自然而然想到的做法是extends该类。而两个类都需要使用Builder进行构造。代码如下&#xff1a; Data Builder AllArgsConstructor NoArgsConstructor public class EmployeeDto {private Stri…

详解 Vue3 中如何使用 Proxy 来实现响应式的技术~

详解 Vue3 中如何使用 Proxy 来实现响应式的技术~写在前面剖析 Vue2 中是如何实现响应式的Vue2 的响应式存在什么问题&#xff1f;Vue3 响应式一、ref 函数二、reactive 函数reactive 响应式原理 - ProxyVue3 中的响应式解决了 Vue2 中存在的问题写在前面 Vue3 中的响应式原理…

C++:STL:常见容器:stack,queue, list

一&#xff1a;stack容器 1.1: stack基本概念 概念&#xff1a;stack是一种先进后出 &#xff08;First in last out FILO&#xff09;的数据结构&#xff0c;它只有一个出口。 栈中&#xff1a; 1&#xff1a;只有栈顶的元素才可以被外界使用&#xff0c;因此栈不允许有遍历…

从FrameDebugger看Unity渲染

从FrameDebugger看Unity渲染(一) Unity如何渲染一个3D2D的游戏画面&#xff0c;今天通过FrameDebugger来看下Unity内置渲染管线的渲染策略, 后续再出一些URP渲染管线相关的文章。 对啦&#xff01;这里有个游戏开发交流小组里面聚集了一帮热爱学习游戏的零基础小白&#xff0c…

MyBatis 实现复杂 Sql 查询

resultMap 结果映射 resultMap 元素是 MyBatis 中最重要最强大的元素&#xff0c;之前所写的 sql 语句&#xff0c;返回值都是简单的基本数据类型或者某一个实体类&#xff0c;比如下面这段 sql 返回的就是最简单的 User 类型。 <select id"getUserById" result…

微信HOOK 协议接口 实战开发篇 3.收发文本消息 附详细步骤

前言&#xff1a;本次文章附带详细的HOOK步骤&#xff0c;感兴趣可以尝试一番 使用了之前文章提到的字符搜索法 接收消息 1.OD打开微信&#xff0c;点击e&#xff0c;进入模块列表 2.双击wechatwin模块进入汇编代码页面 3.右键菜单&#xff0c;选择如图示选项 4.进入字符页…

【 uniapp - 黑马优购 | tabBar】如何创建和配置标签栏

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大二在校生&#xff0c;讨厌编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;小新爱学习. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc…

zabbix监控redis修正nodata问题

之前根据网上的资料尝试监控redis&#xff0c;完成后编写了文档。 https://blog.csdn.net/bigwood99/article/details/128404063 这几天观察数据&#xff0c;发现没有数据被采集。 在图标中显示no data。 检查模板中item和graphs设置&#xff0c;发现key中没有使用引号。 …

修复U盘【笔记】

修复U盘【笔记】前言参考修复U盘问题0.芯片精灵查看1.用APTool软件擦除量产信息2.用CBMTool量产U盘结果我的版本最后前言 以下内容源自网络 仅供学习交流使用 参考 总体步骤&芯片精灵下载&#xff1a;https://www.xpwin7.com/jiaocheng/25627.html 资源下载网址来源&am…

组织上线 | 资源共享,协作自如

新功能&#xff5e;&#xff01;期待已久的组织协作上线啦&#xff01; 上线后支持在组织下创建镜像&#xff0c;组织成员可查看、拉取镜像&#xff0c;快速实现镜像资源共享&#xff0c;组织高效协同。 具体怎么操作呢&#xff1f;跟我一起来看一下吧&#xff5e; 创建组织 …

Pandas计算历史均值

在用Python进行时间序列分析时&#xff0c;我们可能经常需要计算历史的一些特征。一般会使用rolling()函数&#xff0c;这里介绍一下计算包括当前行的历史特征和不包括当前行的历史特征 1. 包括当前行 这里先简单介绍一下rolling()函数 pandas.DataFrame.rolling官方文档 Dat…

数据库,计算机网络、操作系统刷题笔记19

数据库&#xff0c;计算机网络、操作系统刷题笔记19 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;可能很多算法学生都得去找开发&#xff0c;测开 测开的话&#xff0c;你就得学数据库&#xff0c;sql&#xff0c;oracle…

Vue后台项目的记录 (二)

1、品牌静态管理组件 表单 分页器 2、品牌列表展示 创建相关接口文件 获取品牌管理数据的模块 统一接口管理 在main.js中引入&#xff0c;之后在任意组件中就可以使用了 发请求&#xff0c;获取品牌列表的接口 展示数据 current-change"handlecurrentchange curren…

贤鱼的刷题日常(数据结构队列学习)-2406:Card Stacking--题目详解

&#x1f3c6;今日学习目标&#xff1a; &#x1f340;例题讲解2406:Card Stacking ✅创作者&#xff1a;贤鱼 ⏰预计时间&#xff1a;25分钟 &#x1f389;个人主页&#xff1a;贤鱼的个人主页 &#x1f525;专栏系列&#xff1a;c &#x1f341;贤鱼的个人社区&#xff0c;欢…

LabVIEW如何减少下一代测试系统中的硬件过时5

LabVIEW如何减少下一代测试系统中的硬件过时5 Steps to Replace Instruments Performance Requirements The important consideration to make when replacing instruments isthat the replacements must meet your requirements, usually by having equal orbetter measure…

6.1 微服务-Redis

6.1.1 Redis 6.1.1.1 前言 前面使用到的mysql数据库会出现以下问题 由于用户量增大&#xff0c;请求数量也随之增大&#xff0c;数据压力过大 多台服务器之间数据不同步 多台服务器之间的锁&#xff0c;已经不存在互斥性了。 6.1.1.2 Redis 6.1.1.2.1 什么是Redis Redi…

电脑屏幕录制怎么弄,简单好用的3种电脑录屏方法

平时工作或者学习都需要使用电脑进行录屏操作&#xff0c;比如录制线上网课、游戏画面、教学课程录屏等等。电脑屏幕录制怎么弄&#xff1f;可以使用专业录屏软件或者是电脑自带的屏幕录制功能来录屏&#xff1b;今天给大家分享3款简单好用的电脑录屏方法&#xff1b;无论是录制…

2022知识付费小程序源码升级版知识付费变现小程序独立后台版本源码+数据库和教程

知识付费小程序源码升级版主要功能简介&#xff1a; 本源码后台部分是thinkphp开发的&#xff0c;使用和二次开发都非常方便。 会员系统&#xff1a;用户登录/注册购买记录&#xff0c;收藏记录 基本设置&#xff1a;后台控制导航颜色&#xff0c;字体颜色&#xff0c;标题等…

软件测试面试话术 这样准备,让你成功拿到高薪offer

面试就是就是进入岗位前的临门一脚&#xff0c;如果因为准备不足而导致面试失败那可就亏大了&#xff01;因此&#xff0c;为了帮助大家提高面试成功率&#xff0c;尽快拿到高薪offer&#xff0c;我为你们准备了一套面试话术以及技巧&#xff0c;希望对即将参加软件测试面试的你…