C++第十九弹---string模拟实现(下)

个人主页: 熬夜学编程的小林

💗系列专栏: 【C语言详解】 【数据结构详解】【C++详解】

目录

1、修改操作

2、迭代器操作

3、字符串操作 

4、非成员函数重载操作

总结


1、修改操作

1、string& operator+= (const char* s);

//尾部插入字符串s
2、string& operator+= (char c);

//尾部插入字符c
3、void push_back (char c);

//尾部插入字符c
4、string& append (const char* s);

//尾部插入(追加)字符串s
5、void insert(size_t pos, char ch);

//在pos位置插入字符c
6、void insert(size_t pos, const char* str);

//在pos位置插入字符串str
7、void erase(size_t pos, size_t len = npos);

//从pos位置删除n个字符
8、void swap(string& s);

//把字符串数据进行交换

void push_back(char c)
{
	// 扩容 容量为0则固定为4 其他则*2
	if (_size == _capacity)
	{
		reserve(_capacity == 0 ? 4 : 2 * _capacity);
	}
	_str[_size] = c;//_size下标插入字符c
	++_size;//将大小+1
	_str[_size] = '\0';//字符串最后位置给标志结束的\0
}
void append(const char* s)
{
	//追加字符串首先得判断空间是否足够
	size_t len = strlen(s);
	if (len > _capacity - _size)//空间不够则扩容
	{
		reserve(_size + len);//大小为原大小+插入字符串长度
	}

	strcpy(_str + _size, s);//将要追加的数据拷贝到原数据尾
	_size += len;//更新字符串大小
}
string& operator+=(char c)
{
	push_back(c);//调用尾插字符函数

	return *this;
}
string& operator+=(const char* str)
{
	append(str);
	return *this;
}
void insert(size_t pos, char ch)
{
	assert(pos <= _size);//断言,小于字符串大小才能进行插入操作

	// 扩容
	if (_size == _capacity)
	{
		reserve(_capacity == 0 ? 4 : 2 * _capacity);
	}
	// end=_size会有无符号与有符号比较问题,因为pos恒大于等于0,end回到-1
	// 无符号与有符号比较 会提升至无符号比较 即end = -1 还会大于pos
	size_t end = _size + 1;
	while (end > pos)//end==pos则循环停止
	{
		_str[end] = _str[end - 1];//将前面的元素往后面一个位置移动
		--end;
	}
	_str[pos] = ch;//pos位置赋值字符ch
	++_size;//更新大小
}

void insert(size_t pos, const char* str)
{
	assert(pos <= _size);//pos小于字符串大小才能进行插入操作

	size_t len = strlen(str);
	if (len > _capacity - _size)//容量不够则扩容
	{
		reserve(_size + len);
	}
	size_t end = _size + len;
	while (end > pos + len - 1)
	{
		_str[end] = _str[end - len];//将原数据向后移动len位置
		--end;
	}
	strncpy(_str + pos, str, len);//不需要拷贝\0因此使用strncpy拷贝len长度到原串
	_size += len;//更新大小
}
void erase(size_t pos, size_t len = npos)
{
	assert(pos < _size);

	if (len == npos || len >= _size - pos)//长度为npos或者大于等于字符串大小-pos即删除整个字符串
	{
		_str[pos] = '\0';//直接在pos位置给\0即可
		_size = pos;//pos为\0下标,刚还为字符串大小
	}
	else//将pos+len位置后的数据拷贝到pos为止
	{
		strcpy(_str + pos, _str + pos + len);
		_size -= len;//更新长度
	}
}
void swap(string& s)//交换类的成员变量即可,
{
	std::swap(_str, s._str);//调用库函数的swap模板函数
	std::swap(_size, s._size);
	std::swap(_capacity, s._capacity);
}

2、迭代器操作

注意:暂时我们理解的迭代器实质为指针,但不完全是指针,此处就通过指针来模拟实现。

typedef char* iterator;//将迭代器定义成char*类型
typedef const char* const_iterator;将迭代器定义成const char*类型


1、const char* begin() const;

//获取指向首元素的const迭代器
2、const char* end() const;

//获取指向尾元素的const迭代器
3、char* begin();

//获取指向首元素的迭代器
4、char* end();

//获取指向尾元素的迭代器

typedef char* iterator;
typedef const char* const_iterator;

const char* begin() const
{
	return (const char*)_str;//返回首元素地址,const修饰因此强转类型
}
const char* end() const
{
	return (const char*)_str + _size;//尾元素下一个位置地址,即\0位置地址
}
char* begin()
{
	return _str;
}
char* end()
{
	return _str + _size;
}

3、字符串操作 

1、const char* c_str() const;

//获取C字符串首元素地址

2、size_t find(char ch, size_t pos = 0) const;

//从pos位置(默认从0位置)找字符ch,找到则返回下标,否则返回npos
3、size_t find(const char* sub, size_t pos = 0) const;

//从字符串sub的pos位置找是否有匹配的字符串,找到则返回第一个元素下标,否则返回npos
4、string substr(size_t pos = 0, size_t len = npos);

//从pos位置截取len长度(默认截取整个字符串)的子串

const char* c_str() const
{
	return _str;//返回首地址
}
size_t find(char ch, size_t pos = 0) const
{
	assert(pos < _size);//小于字符串大小才能进行查找
	for (size_t i = 0; i < _size; i++)//遍历字符串
	{
		if (_str[i] == ch)
			return i;//找到字符则返回下标
	}
	return npos;
}
size_t find(const char* sub, size_t pos = 0) const
{
	assert(pos < _size);
	const char* p = strstr(sub + pos, _str);//从sub+pos位置找,调用C语言库的找子串函数,找到则返回该值的地址,否则返回NULL
	if (p)//不为空则返回下标,指针相减即为相差个数,即下标
	{
		return p - _str;
	}
	else//为空返回npos
	{
		return npos;
	}
}
string substr(size_t pos = 0, size_t len = npos)
{
	assert(pos < _size);
	string sub;
	if (len >= _size - pos)//长度大于_size-pos即将整个字符串截取,也包括len==npos
	{
		for (size_t i = pos; i < _size; i++)
		{
			sub += _str[i];//追加给sub
		}
	}
	else//否则截取len长度
	{
		for (size_t i = pos; i < len + pos; i++)
		{
			sub += _str[i];
		}
	}
	return sub;
}

4、非成员函数重载操作

1、void swap(string& s1, string& s2);

//将类s1数据与类s2数据交换
2、bool operator==(const string& s1, const string& s2);

//比较s1与s2是否相等
3、bool operator<(const string& s1, const string& s2);

//比较s1是否小于s2
4、ostream& operator<<(ostream& out, const string& s);

//流插入,即打印字符串s
5、istream& operator>>(istream& in, string& s);

//流提取,即将输入的内容给s
6、istream& getline(istream& in, string& s);

//获取一行信息,即将输入中回车之前的信息给s

void swap(string& s1, string& s2)
{
	s1.swap(s2);//调用类成员交换函数,跟库函数中交换函数重载,先调用类成员函数
}
bool operator==(const string& s1, const string& s2)
{
	int ret = strcmp(s1.c_str(), s2.c_str());//调用C语言比较字符串函数,等于0则相等
	return ret == 0;
}
bool operator<(const string& s1, const string& s2)
{
	int ret = strcmp(s1.c_str(), s2.c_str());
	return ret < 0;
}

ostream& operator<<(ostream& out, const string& s)
{
	for (auto ch : s)
	{
		out << ch;//用范围for变量类
	}
	return out;
}

istream& operator>>(istream& in, string& s)
{
	s.clear();//清空串s
	char ch = in.get();//C++库中输入函数,读取一个字符给ch
	char buff[128];//先开辟一个128字节空间,减少频繁扩容
	size_t i = 0;
	while (ch != '\n' && ch != ' ')//流提取不识别空格回车
	{
		buff[i++] = ch;//将字符赋值给buff数组
		if (i == 127)//字符串满了则追加给串s
		{
			buff[127] = '\0';//末尾追加标志符\0
			s += buff;
			i = 0;//再重新赋值字符给buff数组
		}
		ch = in.get();
	}
	if (i > 0)//i>0则再追加数据给s
	{
		buff[i] = '\0';
		s += buff;
	}
	return in;
}
istream& getline(istream& in, string& s)
{
	s.clear();
	char ch = in.get();
	char buff[128];
	size_t i = 0;
	while (ch != '\n')//不识别回车,其他原理同流插入
	{
		buff[i++] = ch;
		if (i == 127)
		{
			buff[127] = '\0';
			s += buff;
			i = 0;
		}
		ch = in.get();
	}
	if (i > 0)
	{
		buff[i] = '\0';
		s += buff;
	}
	return in;
}

总结


本篇博客就结束啦,谢谢大家的观看,如果公主少年们有好的建议可以留言喔,谢谢大家啦!

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

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

相关文章

骑行 - 新区永旺出发的环太湖路线

环过好几次太湖&#xff0c;但对路线都没太在意&#xff0c;都是跟着别人走的。这次自己制定一个路书&#xff0c;方便下次自己一个人环太湖时使用。 开始是使用高德地图做路书&#xff0c;只能在PC上做。我用的是网页版&#xff0c;每次选点太麻烦了。要输入地址搜索&#xff…

【C语言】八进制、十六进制

前言 在我们日常生活中使用的数往往是十进制的&#xff0c;而当我们学习C语言后我们会接触到许多不同的进制并且时常需要去思考与使用这些不同的进制&#xff08;尤其是2的幂相关的进制&#xff0c;因为这种计数系统比十进制更接近于计算机的二进制系统&#xff09;&#xff0…

5.26机器人基础-空间描述和变换2

在前文的基础上引入平移算子和旋转算子 1.平移算子 2.旋转算子 3.变换算子

推荐一款媒体影音嗅探神器—Chrome扩展插件(猫抓cat-catch)

目录 1.1、前言1.2、下载地址1.3、github Releases 版本说明1.4、安装步骤1.5、猫抓插件常规设置1.5.1、设置抓取文件的类型1.5.2、设置抓取文件的后缀名 1.1、前言 我们在日常上网的过程中&#xff0c;很多音频、视频网站下载资源都非常不方便&#xff0c;要么需要安装客户端&…

联邦学习(一)

世界第一本“联邦学习”专著——《联邦学习》。作者阅读数书籍《联邦学习实战》。 1.联邦学习概述 在构件全局模型时,其效果与数据被整合在一起进行集中式训练的效果几乎一致,这便是联邦学习提出的动机和核心思想。 核心理念:数据不动模型动,数据可用不可见。 传统训练范式…

初步认识栈和队列

Hello&#xff0c;everyone&#xff0c;今天小编讲解栈和队列的知识&#xff01;&#xff01;&#xff01; 1.栈 1.1栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。 进行数据插入和删除操作的一端 称为栈顶&…

hsql学习笔记

1. row_number() over (partition by uid order by dt 分析&#xff1a; row_number()&#xff1a; 这是一个窗口函数&#xff0c;用于为结果集中的每一行分配一个唯一的序号。默认情况下&#xff0c;这个序号是按照查询结果的顺序来分配的&#xff0c;但你可以通过OVER()子句…

Mybatis源码剖析---第二讲

Mybatis源码剖析—第二讲 那我们在讲完了mappedstatement这个类&#xff0c;它的一个核心作用之后呢&#xff1f;那下面我有一个问题想问问各位。作为mappedstatement来讲&#xff0c;它封装的是一个select标签或者insert标签。但是呢&#xff0c;我们需要大家注意的是什么&am…

文件夹打开出错?这里有你需要的数据恢复与预防指南

在日常使用电脑时&#xff0c;我们有时会遇到文件夹打开出错的情况。当你尝试访问某个文件夹时&#xff0c;系统可能会弹出一个错误提示&#xff0c;告诉你无法打开该文件夹。这种情况不仅会影响我们的工作效率&#xff0c;还可能导致重要数据的丢失。接下来&#xff0c;我们将…

Java进阶学习笔记24——Object类

Object类: Object类是Java中所有类的祖宗类&#xff0c;因此&#xff0c;Java中所有类的对象都可以直接使用Object类中提供的一些方法。 所有类都是Object类的子孙类。 API文档&#xff1a; Object类的成员方法&#xff1a; Object类的常见方法&#xff1a; Student类&…

HCIP-Datacom-ARST自选题库_02_网络安全【道题】

一、单选题 1.关于网络安全性优化的内容&#xff0c;下列哪个选项是错误的? 管理安全 边界安全 访问控制 日志管理 2.如图所示&#xff0c;网络管理员为了抵御DHcP Server仿冒者攻击&#xff0c;在交换机上部署了DHcp snoping功能&#xff0c;那么以下哪一个接口应该被设…

简单的python程序,把它做成docker镜像

1&#xff0c;python程序准备 在linux主机的/tmp/pythontest路径下创建一个test.py程序文件&#xff0c; 程序内容很简单 就是一句打印 print(hello world, docker)2&#xff0c;再准备一个Dockerfile文件 这个Dockerfile也是放在主机linux中的/tmp/pythontest路径下&#x…

RPA+AI 应用案例集合:自动推流直播

使用场景&#xff1a; 自动定时推流直播 使用技术&#xff1a; python playwright 每个解决一个小问题 During handling of the above exception, another exception occurred:Traceback (most recent call last): File "D:\pythonTryEverything\putdonwphone\not_watch_…

队列(C语言)

文章目录 [TOC](文章目录) 前言1.队列的概念及结构2.队列的实现3.相关操作的具体实现3.1.初始化队列(QueueInit)和销毁队列(QueueDestory)3.2.队尾入队(QueuePush)和队头出队(QueuePop)3.3.判空(QueueEmpty)、获得队尾元素(QueueBack)以及获得队头元素(QueueFront) 前言 前面我…

数据清洗操作及众所周知【数据分析】

各位大佬好 &#xff0c;这里是阿川的博客 &#xff0c; 祝您变得更强 个人主页&#xff1a;在线OJ的阿川 大佬的支持和鼓励&#xff0c;将是我成长路上最大的动力 阿川水平有限&#xff0c;如有错误&#xff0c;欢迎大佬指正 前面的博客 数据分析—技术栈和开发环境搭建 …

如何从零开始搭建公司自动化测试框架?

搭建的自动化测试框架要包括API测试&#xff0c;UI测试&#xff0c;APP测试三类。以上三类其实可以简化为两类&#xff0c;那就是&#xff1a; 1&#xff09;接口自动化测试框架搭建 2&#xff09;UI自动化测试框架搭建。 没问题&#xff0c;安排&#xff0c;且是手把手教你…

国内服务器未备案使用域名443访问的方法

参考国内服务器未备案使用域名443访问的方法 | LogDicthttps://www.logdict.com/archives/guo-nei-fu-wu-qi-wu-fa-shi-yong-yu-ming-de-jie-jue-fang-fa

科林Linux6_网络

#include<sys/socket.h> #include<arpa/inet.h> //大小端转换 #include<netdb.h> //DNS一、Socket套接字 为了开发网络应用&#xff0c;系统提供一套API函数接口&#xff0c;用于网络应用开发&#xff0c;这些接口称为套接字函数 struct sockaddr_in…

【C++ —— 哈希】学习笔记 | 模拟实现封装unordered_map和unordered_set

文章目录 前言一、unordered系列关联式容器1.1 unordered_map1.2 unordered_set 二、底层结构2.1哈希概念&#xff08;哈希是一种算法思想&#xff09;2.2哈希冲突2.3 解决哈希冲突方法&#xff1a;1.直接定址法&#xff08;值和位置关系是唯一关系&#xff0c;每个人都有唯一位…

python画图:matpolt,设置图片尺寸,字体大小,副坐标轴,保存

文章重心: 写论文的时候,图片的大小,字体的大小,副坐标轴,这些都是很重要的因素,保存一下之前用过的画图代码单图多图(两个子图)堆叠柱状图两个Y轴的图问题: python保存的时候,我选择的是svg,但是这样图片会比较大,查重什么的需要把图片都删了(一般有文件大小限制…