C++---string模拟实现

string模拟实现

  • 构造函数和析构函数
  • begin和end
  • reserve和resize
  • push_back和append
  • c_str
  • empty,size,capacity,clear
  • 拷贝构造和赋值
  • +=和比较大小
  • []重载
  • insert和erase
  • find查找

前面我们已经对string进行了简单的介绍,只要会用各个函数即可,下面是string的模拟实现。
在这里我们可以定义一个自己的命名空间,防止与库里的string造成冲突。

namespace haifan
{class string{public:.....private:char* _str;size_t _size;size_t _capacity;};
}

构造函数和析构函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JhE4Trrp-1690193767195)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230724170813742.png)]

这是库里的几种构造函数,在这里,我只实现了一种。

如果在传参的时候我们是以haifan::string a的形式或者是以 haifan::string b("123") 我们可以考虑用 string(const char* str = "") 这样的形式来写构造函数,当没有参数的时候,就用str的缺省值,有参数就用传递的参数。

string(const char* str = "")
{_size = strlen(str);_capacity = _size;_str = new char[_capacity + 1];memcpy(_str, str, _size + 1);
}

析构函数很简单,把_str释放掉,在置为空指针即可

~string()
{delete[] _str;_str = nullptr;_capacity = _size = 0;
}

begin和end

begin和end分别由两种写法,一种是带const的,一种是不带的。

typedef char* iterator;
typedef const char* const_iterator;const_iterator begin() const
{return _str;
}const_iterator end() const
{return _str + _size;
}iterator begin()
{return _str;
}iterator end()
{return _str + _size;
}

reserve和resize

reserve是为字符串预留空间的一个函数,并且只有一个参数,表示要为字符串预留多少空间,如果n要比capacity小,可以不做处理,反之,要为字符串预留n + 1的空间,因为要放一个\0

void reserve(size_t n)
{if (_capacity < n){//注意还有一个\0char* tmp = new char[n + 1];memcpy(tmp, _str, _size + 1);delete[] _str;_str = tmp;_capacity = n;}
}

resize是用字符c来填充多出的元素空间。在改变元素个数时,如果是增多,可能会改变底层容量的大小,如果减少,底层空间总大小不变。

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

push_back和append

push_back是在字符串的尾部,添加一个字符—尾插,但在进行插入的时候,要注意空间是否足够,对此进行一个检查即可。

在插入字符后,别忘了在将\0进行一次尾插

void push_back(char ch)
{if (_size + 1 > _capacity){if (_capacity == 0){reserve(4);}elsereserve(2 * _capacity);}_str[_size++] = ch;_str[_size] = '\0';
}

append是将一个字符串进行尾插,同样,要先进行空间检查。如果空间不足,将空间开辟到跟尾插后的字符串一样的大小即可。

void append(const char* str)
{size_t len = strlen(str);if (len + _size > _capacity){reserve(len + _size);}memcpy(_str + _size, str, len + 1);_size += len;}

c_str

c_str是将string类以C字符串的形式返回。

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

empty,size,capacity,clear

empty用于判断string是否为空。

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

size用于判断string的长度

size_t size() const
{return _size;
}

capacity用于判断string当前的容量

size_t capacity() const
{return _capacity;
}

clear用于清空string,但是capacity并不会被清0

void clear()
{_size = 0;_str[_size] = '\0';
}

拷贝构造和赋值

拷贝构造设计到了空间的开辟,要用深拷贝,浅拷贝可能会造成两个string共用同一块地址。

string(const string& str)
{_str = new char[str._capacity + 1];_size = str._size;_capacity = str._capacity; memcpy(_str, str._str, str._capacity + 1);
}

赋值在这里,只实现了两种情况,一种是 string a = b 另一种是 string a = "abcd",前者利用拷贝构造先创建一个临时变量,然后用swap将*this和tmp进行交换,从而实现=的目的。后者是开辟了一块空间,将str里的内容,拷贝到tmp里面,然后将_str=tmp。

		void swap(string& str){std::swap(_str, str._str);std::swap(_size, str._size);std::swap(_capacity, str._capacity);}string& operator=(const string& s){if (this != &s){string tmp(s);swap(tmp);return *this;}}string& operator= (const char* str){char* tmp = new char[strlen(str) + 1];memcpy(tmp, str, strlen(str) + 1);_size = strlen(str);_capacity = strlen(str) + 1;delete[] _str;_str = tmp;return *this;}

+=和比较大小

加等于一个字符,其实就是尾插

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

加等于一个字符串其实就是append

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

用于比较的代码很好写,只要写出来一个,其他的都可以复用。

比如小于

两种情况 两个string的长度相同或者不相同,如果相同直接memcpy进行字符串的比较即可,如果不相同,看哪个string短,先比短的部分,如果短的部分都相同,则string长的大,如果短的部分不相同,在比较的时候做出判断即可。

		bool operator<(const string& s){if (s._size == _size){return memcpy(_str, s._str, _size);}else{if (_size > s._size){for (int i = 0; i < s._size; i++){if (_str[i] > s._str[i]){return false;}}return false;}else{for (int i = 0; i < _size; i++){if (_str[i] > s._str[i]){return false;}}return true;}}//int ret = memcmp(_str, s._str, _size < s._size ? _size : s._size);//return ret == 0 ? _size < s._size : ret < 0;}一个好理解的写法,一个两行的写法

写出来一个,其他的都可以以<为基础来写

	bool operator<=(const string& s){if (*this < s || *this == s){return true;}return false;}bool operator>(const string& s){return !(*this <= s);}bool operator>=(const string& s){return !(*this < s);}bool operator==(const string& s){return memcpy(_str, s._str, _size) == 0 && _size == s._size;}bool operator!=(const string& s){return !(*this == s);}

[]重载

string类可以像字符串一样,用下表来访问,这是因为把[]进行了重载

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

insert和erase

在第pos位置上插入一个字符,只需要把pos和pos后面的数据向后移动一位即可。

	void insert(size_t pos,char c){assert(pos < _size);if (_size + 1 > _capacity){reserve(2 * _capacity);}size_t tail = _size;size_t head = pos;while (tail >= pos && tail != npos){_str[tail] = _str[tail - 1];tail--;}_str[pos - 1] = c;++_size;_str[_size] = '\0';}	

在pos位置上插入一个字符串,将pos和pos之后的数据,向后移动字符串的长度即可。

	void insert(size_t pos, const char* str){assert(pos < _size);const size_t len = strlen(str);if (len + _size > _capacity){reserve(len + _size);}size_t tail = _size;while (tail >= pos && tail != npos){_str[tail + len] = _str[tail];tail--;}for (int i = 0; i < len; i++){_str[i + pos] = str[i];}_size += len;_str[_size] = '\0';}

erase(size_t pos = 0, size_t len = npos)

pos是要删除的起始位置,len是要删除多少个,不写默认把pos之后的元素全部删除。

npos是 size_t npos = -1,因为size_t是无符号数,-1是一个正数且是一个及其大的值

		void erase(size_t pos = 0, size_t len = npos){assert(pos < _size);if (len + pos > _size){_str[pos] = '\0';_size = pos;}else{size_t tail = pos + len;while (tail < _size){_str[pos++] = _str[tail++];}_size -= len;_str[_size] = '\0';}}

find查找

size_t find(char ch, size_t pos = 0)

从pos位置开始查找某个字符,如果找到了,返回下标,没找到,返回npos

		size_t find(char ch, size_t pos = 0){assert(pos < _size);for (size_t i = pos; i < _size; i++){if (_str[i] == ch){return i;}}return npos;}

size_t find(const char* str, size_t pos = 0)

查找子串,如果找到了,返回第一次找到子串的位置,反之,返回npos

		size_t find(const char* str, size_t pos = 0){assert(pos < _size);const char* ptr = strstr(_str + pos, str);if (ptr){return ptr - _str;}else{return npos;}}

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

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

相关文章

【Boost搜索引擎项目】

文章目录 一、项目流程二、项目展示 一、项目流程 1.编写数据去标签模块–parser.cc 将去标签之后干净文档以title\3content\3url\ntitle\3content\3url\n格式放入同一文件中。 2.建立索引模块–index.hpp 读取处理好的行文本文件进行分词、权重计算等操作&#xff0c;在内存中…

war包读取properties配置文件错误,返回null

现象&#xff1a;使用intellij Idea编写java项目&#xff0c;debug调试时&#xff0c;使用redis.properties文件的类A&#xff0c;A的代码可以使用 “InputStream in RedisUtils.class.getClass().getResourceAsStream("/" proPath);” 方式正常读取redis.propert…

【云驻共创】CodeArts Repo ---高效代码协同开发之旅

目录 一、代码托管发展史 1.1 第一代 1.2 第二代 1.3 第三代 二、CodeArts Repo 介绍 二、CodeArts Repo 功能架构 2.1 研发协同 2.2 代码管理功能 2.3 代码存储特性 三、CodeArts Repo 技术能力 三、华为云代码托管技术发展历程 四、CodeAr…

ubuntu挂载ext4文件系统

文章目录 1.虚拟机分配10G磁盘用来挂载ext4文件系统2.磁盘分区3.创建文件系统4.挂载文件系统5.卸载文件系统6.使用ior测试ext4三种日志模式&#xff08;1&#xff09;ordered&#xff08;2&#xff09;journal&#xff08;3&#xff09;writeback 1.虚拟机分配10G磁盘用来挂载e…

SpringBoot项目修改Tomcat版本号

SpringBoot项目修改Tomcat版本号 前言如果项目是以jar包形式打包部署如果项目是以war包形式打包部署示例 仰天大笑出门去&#xff0c;我辈岂是蓬蒿人 前言 Springboot项目,默认是使用内嵌Tomcat servlet容器形式打包部署。关于怎么修改默认的版本号&#xff0c;捣鼓了好久终于…

PostgreSQL 设置时区,时间/日期函数汇总

文章目录 前言查看时区修改时区时间/日期操作符和函数时间/日期操作符日期/时间函数&#xff1a;extract&#xff0c;date_part函数支持的field 数据类型格式化函数用于日期/时间格式化的模式&#xff1a; 扩展 前言 本文基于 PostgreSQL 12.6 版本&#xff0c;不同版本的函数…

基于STM32设计的人体健康监护系统(华为云IOT)

一、设计需求 1.1 设计需求总结 根据需求,要求设计一款基于 STM32 的人体健康监护系统。采用系统模块化思路进行,将多个数模传感器收集到的数据和操作指令一并送至 STM32 中心处理器进行处理分析。 该系统可以实时监测被测者的心率、体温以及周围环境的温度,也同时可以通…

(vue)vue项目中引入外部字体

(vue)vue项目中引入外部字体 效果&#xff1a; 第一步 放置字体包&#xff0c;在assets下创建一个fonts文件夹&#xff0c;放入下载的字体文件 第二步 创建一个font.css文件用于定义这个字体包的名字 第三步 在App.vue的css中将这个css文件引入 第四步 页面使用 font-famil…

Qt : day1

1.聊天界面 #include "widget.h"Widget::Widget(QWidget *parent): QWidget(parent) {qDebug() << this->size(); //获取当前页面尺寸this->setFixedSize(500, 600); //设置固定尺寸this->setWindowTitle("聊天框"); //设置窗口…

单Bank OTA升级:STM32G071 APP (二)

接上一篇文章&#xff1a;单Bank OTA升级&#xff1a;STM32G071 BootLoader (一)&#xff1a;跳转链接 什么是单Bank升级&#xff1a;将Flash划分为以下3个区域。 BootLoader区&#xff1a;程序进行升级的引导程序&#xff0c;根据Upade_Flag来判断跳转Bank区运行程序或是接收…

SSL证书是什么?

SSL证书是什么&#xff1a;SSL证书&#xff08;Secure Sockets Layer Certificate&#xff09;是一种数字证书&#xff0c;用于在计算机网络上进行安全通信。它可以验证通信双方的身份&#xff0c;并通过加密传输数据来实现安全通信。 SSL证书申请&#xff1a;通常&#xff0c…

安卓开发后台应用周期循环获取位置信息上报服务器

问题背景 最近有需求&#xff0c;在APP启动后&#xff0c;退到后台&#xff0c;还要能实现周期获取位置信息上报服务器&#xff0c;研究了一下实现方案。 问题分析 一、APP退到后台后网络请求实现 APP退到后台后&#xff0c;实现周期循环发送网络请求。目前尝试了两种方案是…

Spring 中一个少见的引介增强 IntroductionAdvisor

我们平时做 AOP 开发的时候&#xff0c;基本上都是增强某一个方法&#xff0c;在某一个方法执行之前或者执行之后做一些事情&#xff0c;这种叫做 PointcutAdvisor&#xff0c;实际上&#xff0c;Spring 中的 Advisor 大致可以分为两种类型&#xff0c;除了 PointcutAdvisor 之…

Openlayers实战,Openlayers实现一个车辆转向运动轨迹动画,支持根据轨迹运动方向自动改变车头转向角度,无需定时器,丝滑小车转向运动效果

专栏目录: OpenLayers入门教程汇总目录 前言 本章作为OpenLayers入门文章《OpenLayers入门,OpenLayers动画效果实现,OpenLayers实现轨迹运动动画》的的增强进阶篇章,实现了入门教程中没有实现的小车车头方向根据运动方向自动转向的功能。 本章代码不使用任何setTimeout和…

金融中的数学:贝叶斯公式

1.贝叶斯定理 贝叶斯定理是概率论中的一项重要定理&#xff0c;用于在已知某一事件的条件下&#xff0c;求另一事件发生的概率。它是根据条件概率推导出来的&#xff0c;得名于英国数学家托马斯贝叶斯。 贝叶斯定理可以表示为&#xff1a; 这个式子就是贝叶斯公式&#xff0c…

解决FLink:Missing required options are: slot.name

[ERROR] Could not execute SQL statement. Reason: org.apache.flink.table.api.ValidationException: One or more required options are missing.Missing required options are:slot.name解决 https://ververica.github.io/flink-cdc-connectors/release-2.4/content/connec…

提升 API 可靠性的五种方法

API 在我们的数字世界中发挥着关键的作用&#xff0c;使各种不同的应用能够相互通信。然而&#xff0c;这些 API 的可靠性是保证依赖它们的应用程序功能正常、性能稳定的关键因素。本文&#xff0c;我们将探讨提高 API 可靠性的五种主要策略。 1.全面测试 要确保 API 的可靠性…

二进制重排

二进制重排作用 二进制重排的主要目的是将连续调用的函数连接到相邻的虚拟内存地址&#xff0c;这样在启动时可以减少缺页中断的发生&#xff0c;提升启动速度。目前网络上关于ios应用启动优化&#xff0c;通过XCode实现的版本比较多。MacOS上的应用也是通过clang进行编译的&am…

Seata部署(Centos和Docker)

一、简介 Seata 是一款开源的分布式事务框架。致力于在微服务架构下提供高性能和简单易用的分布式事务服 务。在 Seata 开源之前&#xff0c;Seata 对应的内部版本在阿里经济体内部一直扮演着分布式一致性中间件的⻆ 色&#xff0c;帮助经济体平稳的度过历年的双11&#xff0c…

11 spring-boot的MVC配置原理

11.1 spring-boot为MVC提供的自动配置 1.ContentNegotiatingViewResolver视图解析器&#xff1b; 2.静态资源或者支持WebJars&#xff1b; 3.自动注册类型转换器&#xff1a;比如说前台提交user的字段&#xff0c;后台自动封装的意思&#xff1b; 4.HttpMessageConverters&…