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

news2024/9/20 1:08:28

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

💗系列专栏: 【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;
}

总结


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

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

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

相关文章

科林Linux6_网络

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

【STM32】计算定时器的溢出

TIM2、3、4、5、12、13、14在APB1上&#xff0c;最大计数频率84M。 TIM1、8、9、10、11在APB2上&#xff0c;最大计数频率168M。 time(arr1)/(prescale1)/Tclk 算出来的是秒 下图使用TIM14 84MHz 那么time33600*25000/8400000010S&#xff0c;10S进入一次中断 中断方式开…

【脚本篇】---spyglass lint脚本

目录结构 sg_lint.tcl &#xff08;顶层&#xff09; #1.source env #date set WORK_HOME . set REPORT_PATH ${WORK_HOME}/reports puts [clock format [clock second] -format "%Y-%m-%d %H:%M:%S"] #2.generate source filelist #3.set top module puts "##…

BFS 解决最短路问题

目录 一、前言 1.1 如何使用 BFS 找到最短路&#xff1a; 1.2 为什么不用 dfs &#xff1a; 二、模板套路 三、例题练习 3.1 例题1&#xff1a;迷宫中离入口最近的出口 3.2 例题2&#xff1a;最小基因变化 3.3 例题3&#xff1a;单词接龙 3.4 例题4&#xff1a;为高尔…

Springboot+Vue+ElementUI开发前后端分离的员工管理系统01--系统介绍

项目介绍 springboot_vue_emp是一个基于SpringbootVueElementUI实现的前后端分离的员工管理系统 功能涵盖&#xff1a; 系统管理&#xff1a;用户管理、角色管理、菜单管理、字典管理、部门管理出勤管理&#xff1a;请假管理、考勤统计、工资发放、工资统计、离职申请、个人资…

低频量化周报(指数分位值,指数风险溢价比,配债完整数据集,可转债策略)...

低频量化周报&#xff08;2024-05-25&#xff09; 指数分位值指数风险溢价比小规模配债<5亿配债完整数据 5 批文通过4 发哥通过3 交易所受理2 股东大会通过1 董事会预案可转债策略 双低策略四因子策略网格策略ETF抄底指标<3历史操作记录本周心得最后 指数分位值 指数名称…

秋招突击——算法打卡——5/25、5/26——寻找两个正序数组的中位数

题目描述 自我尝试 首先&#xff0c;就是两个有序的数组进行遍历&#xff0c;遍历到一半即可。然后求出均值&#xff0c;下述是我的代码。但这明显是有问题的&#xff0c;具体错误的代码如下。计算复杂度太高了&#xff0c;O&#xff08;n&#xff09;&#xff0c;所以会超时&…

2024年【高压电工】新版试题及高压电工找解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 高压电工新版试题是安全生产模拟考试一点通生成的&#xff0c;高压电工证模拟考试题库是根据高压电工最新版教材汇编出高压电工仿真模拟考试。2024年【高压电工】新版试题及高压电工找解析 1、【单选题】 110KV及以下…

C++课程设计:学校人员信息管理系统(可视化界面)

目录 学校人员信息管理系统 操作演示 MP4转GIF动图 设计功能要求 评分标准 QT Creator安装和新建项目 QT安装 QT新建项目 管理系统程序设计 mainwindow.h 文件 mainwindow.h 程序释义 mainwindow.cpp 文件 mainwindow.cpp 程序释义 main.h 文件 TXT文件生成 博主…

redis6.2.7 搭建一主多从

1、集群规划 节点端口角色192.168.137.1026379master192.168.137.1026380slave192.168.137.1036381slave 2、伪集群搭建 2.1 创建fake_cluster 目录存放 公共配置文件 # 进入redis目录 cd /app/apps/redis-6.2.7# 创建存放伪集群的目录 mkdir fake_cluster#复制redis.conf到…

东方通TongWeb结合Spring-Boot使用

一、概述 信创需要; 原状:原来的服务使用springboot框架,自带的web容器是tomcat,打成jar包启动; 需求:使用东方通tongweb来替换tomcat容器; 二、替换步骤 2.1 准备 获取到TongWeb7.0.E.6_P7嵌入版 这个文件,文件内容有相关对应的依赖包,可以根据需要来安装到本地…

【Qt 学习笔记】Qt窗口 | 菜单栏 | QMenuBar的使用及说明

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Qt窗口 | 菜单栏 | QMenuBar的使用及说明 文章编号&#xff1a;Qt 学习…

顺序栈的实现

顺序栈是用数组实现的&#xff1a;&#xff08;假设我们有8个位置&#xff08;下标0-7&#xff09;&#xff09; #include<stdio.h> #include<malloc.h> #include<assert.h> #include <iostream> #define MAX_SIZE 8#define Elemtype int typedef str…

Android 配置 Kapt 编译器插件

以 Android Studio 2023.3.1 最新版本为准。 步骤1:打开版本信息配置文件 找到libs.versions.toml文件。 这是打开后的样子&#xff1a; 步骤2&#xff1a;配置版本信息 你需要在[plugins]下面添加一条kapt的配置信息&#xff1a; 要添加的配置信息如下&#xff1a; jetbr…

YOLOv8_pose的训练、验证、预测及导出[关键点检测实践篇]

1.关键点数据集划分和配置 从上面得到的数据还不能够直接训练,需要按照一定的比例划分训练集和验证集,并按照下面的结构来存放数据,划分代码如下所示,该部分内容和YOLOv8的训练、验证、预测及导出[目标检测实践篇]_yolov8训练测试验证-CSDN博客是重复的,代码如下: …

粒子辐照环境中相机镜头防护及LabVIEW图像处理注意事项

在粒子辐照环境测试电路板性能的实验中&#xff0c;需要对相机镜头进行有效防护&#xff0c;同时利用LabVIEW进行图像识别和处理。本文将讨论相机镜头防护的关键因素和LabVIEW处理过程中的注意事项&#xff0c;包括防辐射材料选择、辐射屏蔽措施、散热管理、空间布局及LabVIEW软…

CorelCAD v2022.5 解锁版 安装教程(2D制图 3D设计和打印的简化软件)

前言 CorelCAD&#xff0c;加拿大Corel公司开发的一款适用于2D制图、3D设计和打印的简化版CAD软件。它是款专业的2D制图和3D设计软件&#xff0c;拥有行业标准文件兼容性&#xff0c;支持 .DWG、.STL、.PDF、 .CDR*等文件格式&#xff0c;轻松实现协作和项目共享&#xff0c;利…

6818 android 修改开机 logo, 编译脚本分析

问题&#xff1a; 客户需要去掉 android5.1 的开机logo. 说明&#xff1a; 对于Android5.1 来说&#xff0c;uboot 与kernel 的logo 是一个。 过程&#xff1a; 其实对于开机logo 的修改很简单&#xff0c;直接参考厂家手册就可以了。 这是 android4.4 的开机logo 的修改&…

Qt | QStackedLayout 类(分组布局或栈布局)、QStackedWidget

01、QStackedLayout 类 1、使用 QStackedLayout 可以实现一个多页面切换的界面,多 页面切换就是类似于选项卡(如右图)类型的界面。 2、QStackedLayout 并没有直接实现多页面切换的办面,只是我们可以通过该类实现多页面切 换的功能,因此要使用 QStackedLayout 类实现多面面…

LeetCode 第399场周赛个人题解

100323. 优质数对的总数 I 原题链接 100323. 优质数对的总数 I 思路分析 签到题 AC代码 class Solution:def numberOfPairs(self, nums1: List[int], nums2: List[int], k: int) -> int:n, m len(nums1), len(nums2)ret 0for i in range(n):for j in range(m):if nu…