【C++】模拟实现string


目录
🌞专栏导读
🌛定义string类
🌛构造函数
🌛拷贝构造函数
🌛赋值函数
🌛析构函数
🌛[]操作符重载
🌛c_str、size、capacity函数
🌛比较运算符重载
🌛resize与reserve函数
🌛push_back、append函数
🌛insert函数
🌛erase函数
🌛find函数
🌛swap函数
🌛clean函数
🌛迭代器
🌛>> 与 << 重载
🌞专栏导读
🌟作者简介:日出等日落,在读本科生一枚,致力于 C/C++、Linux 学习。
🌟本文收录于 C++系列,本专栏主要内容为 C++ 初阶、C++ 进阶、STL 详解等,持续更新!
🌟相关专栏推荐:C语言系列 、Linux系列 、数据结构与算法
本章我们将模拟实现string类,但不一定非要与库中完全相同。我们将其中重要的、常用的接口进行模拟实现,旨在加深string类的学习与记忆。
🌛定义string类
为了区别于标准库中的string,这里使用自己的命名空间,在自己的命名空间模拟实现string
string类包含这三个基本成员:
char* _str字符数组;size_t _size有效字符大小;size_t _capacity容量;
此外还需声明一个static成员npos,npos为将来实现的某些成员函数的缺省值,值位-1;
namespace yxb
{class string{public:private:char* _str;size_t _capacity;size_t _size;//类中声明static const size_t npos;};//类外定义const size_t string::npos = -1;
}
🌛构造函数
//构造函数string(const char* str = "") //使用缺省值:_size(strlen(str)){_capacity = _size == 0 ? 3 : _size; //_capacity初始值不能为0_str = new char[_capacity + 1]; //为'\0'预留位置strcpy(_str, str);}
注意
_capacity的值不能初始化为0,因为扩容时可能出现0*n=0的情况。
🌛拷贝构造函数
拷贝构造虽然编译器会自动实现,但是自动实现的拷贝构造为浅拷贝,对于string类中,成员变量会申请资源的情况,浅拷贝是行不通的,所以需要我们自己实现。
//拷贝构造s3(s2)string(const string& s):_size(s._size),_capacity(s._capacity){_str = new char[s._capacity + 1];strcpy(_str, s._str);}
🌛赋值函数
//s1 = s3 s1 = s1string& operator=(const string& s){if (this != &s){char* tmp = new char[s._capacity + 1];strcpy(tmp,s._str);delete[] _str;_str = tmp;_size = s._size;_capacity = s._capacity;}return *this;}
🌛析构函数
~string(){delete[] _str;_str = nullptr;_capacity = _size = 0; }
🌛[]操作符重载
注意应对const对象与非const对象须实现不同的重载函数。
char& operator[](size_t pos){assert(pos < _size);return _str[pos];}const char& operator[](size_t pos)const{assert(pos < _size);return _str[pos];}
🌛c_str、size、capacity函数
c_str:返回C风格的字符串。size:返回_size;capacity:返回_capacity;
const char* c_str(){return _str;}size_t size() const{return _size;}size_t capacity() const{return _capacity;}
🌛比较运算符重载
//比较运算符重载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 *this > s && *this == s;}bool operator<(const string& s) const{return !(*this >= s);}bool operator<=(const string& s) const{return !(*this > s);}bool operator!=(const string& s) const{return !(*this == s);}
🌛resize与reserve函数
resize:扩容并初始化;reserve:只扩容;
//扩容void reverse(size_t n){if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}}//扩容+初始化void resize(size_t n, char ch = '\0'){if (n <= _size){//删除数据,保留前n个_size = n;_str[_size] = '\0';}else{if (n > _capacity){reverse(n);}size_t i = _size;while (i < n){_str[i++] = ch;}_size = n;_str[_size] = '\0';}}
🌛push_back、append函数
push_back:尾插一个字符;append:尾插一个字符串;+=:尾插一个字符或字符串;
void push_back(char ch){if (_size + 1 > _capacity){reverse(_capacity * 2);}_str[_size] = ch;_size++;_str[_size] = '\0';}void append(const char* str){size_t len = strlen(str);if (_size + len > _capacity){reverse(_size + len);}strcpy(_str + _size, str);_size += len;}string& operator+=(char ch){push_back(ch);return *this;}string& operator+=(const char* str){append(str);return *this;}
🌛insert函数
insert:在pos位置插入一个字符或字符串;
void insert(size_t pos, char ch){assert(pos <= _size);if (_size + 1 > _capacity){reverse(2 * _capacity);}size_t end = _size + 1;while (pos < end){_str[end] = _str[end - 1];end--;}_str[pos] = ch;_size++;}void insert(size_t pos, const char* str){assert(pos <= _size);size_t len = strlen(str);if (_size + len > _capacity){reverse(_size + len);}//挪动数据size_t end = _size + len;while ( end > pos +len-1 ){_str[end] = _str[end-len];end--;}//拷贝插入 strncpy(_str + pos, str, len);_size += len;}
🌛erase函数
erase:删除pos位置向后的n个字符;
void erase(size_t pos, size_t len = npos){if (len == npos || pos + len >= _size){_str[pos] = '\0';_size = pos;}//0123456789else{strcpy(_str + pos, _str + pos + len);_size -= pos;}}
🌛find函数
find:从pos位置开始向后查找指定字符或字符串,并返回起始位置的下标。
size_t find(char ch, size_t pos = npos){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 = npos){assert(pos < _size);char* p = strstr(_str, str);if (p == nullptr){return npos;}else{return p - str;}}
🌛swap函数
void swap(string& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}
🌛clean函数
clean:清理数据;
void clean(){_str[0] = '\0';_size = 0;}
🌛迭代器
//迭代器typedef char* iterator;typedef const char* const_iterator;iterator begin(){return _str;}iterator end(){return _str + _size;}const_iterator begin() const{return _str;}const_iterator end()const{return _str + _size;}
🌛>> 与 << 重载
注意这两个函数须定义在类外。
ostream& operator<<(ostream& out, const string& str){for (auto ch : str){out << ch;}return out;}istream& operator>>(istream& in, string& str){str.clean();char ch = in.get();char buff[128]; //避免因频繁扩容导致效率过低size_t i = 0;while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == 127){buff[127] = '\0';str += buff;i = 0;}ch = in.get();}if (i != 0){buff[i] = '\0';str += buff;}return in;}
🌛完整代码
#pragma once
#include<assert.h>namespace yxb
{class string{public:typedef char* iterator;typedef const char* const_iterator;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 = ""):_size(strlen(str)){_capacity = _size == 0 ? 3 : _size;_str = new char[_capacity + 1];strcpy(_str, str);}//拷贝构造s3(s2)string(const string& s):_size(s._size),_capacity(s._capacity){_str = new char[s._capacity + 1];strcpy(_str, s._str);}//s1 = s3 s1 = s1string& operator=(const string& s){if (this != &s){char* tmp = new char[s._capacity + 1];strcpy(tmp,s._str);delete[] _str;_str = tmp;_size = s._size;_capacity = s._capacity;}return *this;}~string(){delete[] _str;_str = nullptr;_capacity = _size = 0; }const char* c_str(){return _str;}char& operator[](size_t pos){assert(pos < _size);return _str[pos];}const char& operator[](size_t pos)const{assert(pos < _size);return _str[pos];}size_t size()const{return _size;}size_t capacity()const{return _capacity;}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 (*this == s || *this > s);}bool operator<(const string& s)const{return !(*this >= s);}bool operator<=(const string& s)const{return !(*this > s);}bool operator!=(const string& s)const{return !(*this == s);}//扩容void reverse(size_t n){if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}}//扩容+初始化void resize(size_t n, char ch = '\0'){if (n <= _size){//删除数据,保留前n个_size = n;_str[_size] = '\0';}else{if (n > _capacity){reverse(n);}size_t i = _size;while (i < n){_str[i++] = ch;}_size = n;_str[_size] = '\0';}}void push_back(char ch){if (_size + 1 > _capacity){reverse(_capacity * 2);}_str[_size] = ch;_size++;_str[_size] = '\0';}void append(const char* str){size_t len = strlen(str);if (_size + len > _capacity){reverse(_size + len);}strcpy(_str + _size, str);_size += len;}string& operator+=(char ch){push_back(ch);return *this;}string& operator+=(const char* str){append(str);return *this;}void insert(size_t pos, char ch){assert(pos <= _size);if (_size + 1 > _capacity){reverse(2 * _capacity);}size_t end = _size + 1;while (pos < end){_str[end] = _str[end - 1];end--;}_str[pos] = ch;_size++;}void insert(size_t pos, const char* str){assert(pos <= _size);size_t len = strlen(str);if (_size + len > _capacity){reverse(_size + len);}//挪动数据size_t end = _size + len;while ( end > pos +len-1 ){_str[end] = _str[end-len];end--;}//拷贝插入 strncpy(_str + pos, str, len);_size += len;}void erase(size_t pos, size_t len = npos){if (len == npos || pos + len >= _size){_str[pos] = '\0';_size = pos;}//0123456789else{strcpy(_str + pos, _str + pos + len);_size -= pos;}}size_t find(char ch, size_t pos = npos){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 = npos){assert(pos < _size);char* p = strstr(_str, str);if (p == nullptr){return npos;}else{return p - str;}}void swap(string& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}void clean(){_str[0] = '\0';_size = 0;}private:char* _str;size_t _capacity;size_t _size;static const size_t npos;};const size_t string::npos = -1;ostream& operator<<(ostream& out, const string& str){for (auto ch : str){out << ch;}return out;}istream& operator>>(istream& in, string& str){str.clean();char ch = in.get();char buff[128]; //避免因频繁扩容导致效率过低size_t i = 0;while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == 127){buff[127] = '\0';str += buff;i = 0;}ch = in.get();}if (i != 0){buff[i] = '\0';str += buff;}return in;}void test_string1(){ string s1;string s2("hello world");cout << s1.c_str() << endl;cout << s2.c_str() << endl;s2[0]++;cout << s2.c_str() << endl;}void test_string2(){string s1;string s2("hello world");cout << s1.c_str() << endl;cout << s2.c_str() << endl;s1 = s2;cout << s1.c_str() << endl;cout << s2.c_str() << endl;}void test_string3(){string s1;string s2("hello world");cout << s1.c_str() << endl;cout << s2.c_str() << endl;string::iterator it = s2.begin();while (it != s2.end()){cout << *it << endl;++it;}}void test_string4(){string s1;string s2("hello world");string s3("hello");cout << s1.c_str() << endl;cout << s2.c_str() << endl;cout << (s3 >= s2) << endl;}void test_string5(){string s1;string s2("hello world");s2.append("yyyyyy");cout << s2.c_str() << endl;}void test_string6(){string s1("hhh ");cout << s1.c_str() << endl;s1.resize(10, 'x');cout << s1.c_str() << endl;s1.resize(100, 'y');cout << s1.c_str() << endl;}void test_string7(){string s1("123456789");cout << s1.c_str() << endl;s1.insert(2, "wwww");cout << s1.c_str() << endl;s1.insert(0, "ss");cout << s1.c_str() << endl;}void test_string8(){string s1("123456789");cout << s1.c_str() << endl;s1.erase(4, 2);cout << s1.c_str() << endl;}void test_string9(){string s1;cin >> s1;cout << s1 << endl;}
}

相关文章:
【C++】模拟实现string
目录 🌞专栏导读 🌛定义string类 🌛构造函数 🌛拷贝构造函数 🌛赋值函数 🌛析构函数 🌛[]操作符重载 🌛c_str、size、capacity函数 🌛比较运算符重载 &#…...
AI智慧安监视频监控汇聚平台EasyCVR调用接口出现跨域现象该如何解决?
视频监控汇聚EasyCVR可拓展性强、视频能力灵活、部署轻快,可支持的主流标准协议有GB28181、RTSP/Onvif、RTMP等,以及厂家私有协议与SDK接入,包括海康Ehome、海大宇等设备的SDK等,能对外分发RTSP、RTMP、FLV、HLS、WebRTC等格式的视…...
无人机机巢有哪些,无人机机场/机场的主要分类
随着无人机技术的飞速发展,无人机已经渗透到了物流、农业、救援、公共安全等多个领域。而为了使这些无人机能更加高效、灵活地运行,一个新的概念应运而生,那就是无人机机巢(UAV Nest)。复亚智能无人机机巢是一种供无人…...
联想存储 HH0305_DE4000H 划分卷组、卷、主机
创建卷组 可使用卷组来创建可供主机访问的一个或多个卷。卷组是具有共同特性(如 RAID 级别和容量)的卷的容器。 关于本任务 如果拥有容量较大的驱动器且可以在控制器之间分发卷,则为每个卷组创建多个卷可以很好地利用存储容量和保护数据。…...
【Python机器学习】实验08 决策树
文章目录 决策树1 创建数据2 定义香农信息熵3 条件熵4 信息增益5 计算所有特征的信息增益,选择最优最大信息增益的特征返回6 利用ID3算法生成决策树7 利用数据构造一颗决策树Scikit-learn实例决策树分类决策树回归Scikit-learn 的决策树参数决策树调参 实验1 通过sk…...
MySQL的innoDB存储引擎如何解决幻读的问题?
MySQL的innoDB存储引擎如何解决幻读的问题 基本情况 MySQL有四种事务隔离级别,这四种隔离级别代表当存在多个事务并发冲突时,可能出现的脏读、不可重复读、幻读的问题InnoDB 在 RR 的隔离级别下 ,解决了幻读的问题幻读是指在同一个事务中&a…...
Web3.0:重新定义互联网的未来
💗wei_shuo的个人主页 💫wei_shuo的学习社区 🌐Hello World ! Web3.0:重新定义互联网的未来 Web3.0是指下一代互联网,也称为“分布式互联网”。相比于Web1.0和Web2.0,Web3.0具有更强的去中心化、…...
2023年还能选择前端吗?
前言 在Github2022的 Octoverse年度报告上,稳居最多使用榜首的语言可以看到是JavaScript,作为前端中最为关键的一部分,这说明即使现在,前端这一块仍然是大量的人涌进来,依然是火热,但是,一门语…...
sheetJs / xlsx-js-style 纯前端实现导出 excel 表格及自定义单元格样式
文章目录 一、安装二、创建基础工作表三、设置单元格宽度/高度/隐藏单元格四、分配数字格式五、超链接六、单元格注释七、公式八、合并单元格九、自定义单元格样式十、项目地址 一、安装 xlsx 地址:https://www.npmjs.com/package/xlsxSheetJs 地址:htt…...
Redis 报错 RedisConnectionException: Unable to connect to x.x.x.x:6379
文章目录 Redis报错类型可能解决方案 Redis报错类型 org.springframework.data.redis.connection. spingboot调用redis出错 PoolException: Could not get a resource from the pool; 连接池异常:无法从池中获取资源; nested exception is io.lettuce.core. 嵌套异常 RedisConn…...
Stable Diffusion - 真人照片的高清修复 (StableSR + GFPGAN) 最佳实践
欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/132032216 GFPGAN (Generative Facial Prior GAN) 算法,用于实现真实世界的盲脸恢复的算法,利用预训练的面部 GAN…...
细讲一个 TCP 连接能发多少个 HTTP 请求(一)
一道经典的面试题是从 URL 在浏览器被被输入到页面展现的过程中发生了什么,大多数回答都是说请求响应之后 DOM 怎么被构建,被绘制出来。但是你有没有想过,收到的 HTML 如果包含几十个图片标签,这些图片是以什么方式、什么顺序、建…...
了解 CVSS:通用漏洞评分系统的应用
漏洞威胁管理至关重要,因为网络犯罪是一种持续存在的全球风险。网络犯罪分子愿意利用软件中的任何漏洞来访问网络和设备。对使用该软件的软件开发人员和组织的影响可能很严重。用户必须处理攻击的结果,例如赎金或数据盗窃,并且还可能面临法律…...
Xilinx FPGA电源设计与注意事项
1 引言 随着半导体和芯片技术的飞速发展,现在的FPGA集成了越来越多的可配置逻辑资源、各种各样的外部总线接口以及丰富的内部RAM资源,使其在国防、医疗、消费电子等领域得到了越来越广泛的应用。当采用FPGA进行设计电路时,大多数FPGA对上电的…...
前端:地图篇(一)
1、前言 在很多的出行程序中,都会使用到地图这一个功能,在实际的开发中我们也不会去开发一个自己的地图模型。如果自己开发一个地图模型,那么需要投入的成本、人力都是非常巨大的。所以我们很多网站和APP中使用的都是第三方的接口和JS&#…...
刷题笔记 day6
力扣 57 和为s的两个整数 class Solution { public:vector<int> twoSum(vector<int>& nums, int target) {vector<int> v;int i 0 , j nums.size()-1;while(i < j){if(nums[i] nums[j] > target){--j;}else if(nums[i] nums[j] < target){i…...
Drools用户手册翻译——第四章 Drools规则引擎(十一)复杂事件处理(CEP)的属性更改设置和监听器
甩锅声明:本人英语一般,翻译只是为了做个笔记,所以有翻译错误的地方,错就错了,如果你想给我纠正,就给我留言,我会改过来,如果懒得理我,就直接划过即可。 事实类型的属性…...
[数据分析与可视化] Python绘制数据地图4-MovingPandas入门指北
MovingPandas是一个基于Python和GeoPandas的开源地理时空数据处理库,用于处理移动物体的轨迹数据。它提供了一组强大的工具,可以轻松地加载、分析和可视化移动物体的轨迹。通过使用MovingPandas,用户可以轻松地处理和分析移动对象数据&#x…...
基于SpringBoot+Vue的MOBA类游戏攻略分享平台设计与实现(源码+LW+部署文档等)
博主介绍: 大家好,我是一名在Java圈混迹十余年的程序员,精通Java编程语言,同时也熟练掌握微信小程序、Python和Android等技术,能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…...
Linux sed 命令详解
Linux sed(Stream Editor)是一种强大的文本处理工具,它在命令行中执行对文本进行搜索、替换和编辑等操作。sed的设计理念是按行处理文本,可以将输入文本逐行读取并应用指定的操作,然后输出结果。 sed命令有多种选项和…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...
理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...
04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...
高防服务器能够抵御哪些网络攻击呢?
高防服务器作为一种有着高度防御能力的服务器,可以帮助网站应对分布式拒绝服务攻击,有效识别和清理一些恶意的网络流量,为用户提供安全且稳定的网络环境,那么,高防服务器一般都可以抵御哪些网络攻击呢?下面…...
Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...
20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...
Python Ovito统计金刚石结构数量
大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...
