【C++】——string模拟实现

前言

string的模拟实现其实就是增删改查,只不过加入了类的概念。

为了防止与std里面的string冲突,所以这里统一用String。

目录

前言

一   初始化和销毁 

1.1  构造函数

1.2  析构函数

 二  迭代器实现

三  容量大小及操作

 四 运算符重载

 4.1  bool operator<(const String& s) const

4.2  bool operator==(const String& s) const 

 4.3  bool operator<=(const String& s) const

4.4 bool operator>(const String& s) const

4.5  bool operator>=(const String& s) const 

 4.6  bool operator!=(const String& s) const

 五  字符串操作 

5.1  截取操作

5.2  查找操作

六  流插入流提取

6.1  ostream& operator<<(ostream& out, const String& s)

6.2   istream& operator>>(istream& in, String& s)

 七  string与string相加

String operator+(const String& s2)

string类模拟实现完整代码

总结


一   初始化和销毁 

1.1  构造函数

对于构造函数来说有有参构造和无参构造

所以直接把他们结合起来

default 
string();
copy 
string (const string& str);

 1.string();//无参构造

2.string (const string& str);//有参构造

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

 如果把_str的初始化放在初始化列表会出问题

private:char* _str;size_t _size;size_t _capacity;static const size_t npos = -1;
String(const char* str = "") :_str(new char [_capacity+1]),_size(strlen(str)), _capacity(_size){//_str = new char[_capacity+1];strcpy(_str, str);}

初始化列表是会按照成员变量的顺序去初始化,所以这里 初始化_str,_capacity没有初始化,所以在开空间的时候会出问题,当然你可以换一换位置,但是未免太繁琐,同时这里不能把_str设置为nullptr,如果设置为空,那么_size正初始化就会出问题

1.2  析构函数

 这里的析构函数没有那么多细节,直接释放空间,然后处理其他的成员变量就行了

~String(){delete[] _str;//注意这里的delete[],不是delete_str = nullptr;_size = 0;_capacity = 0;}

 二  迭代器实现

其实迭代器可以理解为是指针在进行,有的底层是指针有的是其他的方法,这里我们用指针去模拟实现

//迭代器typedef char* iterator;typedef 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;}

迭代器也需要const类型,这样const类型的函数才能去调用,所以写两份。注意范围for就是无脑替换迭代器,本质和迭代器是一样的。

测试案例

#define _CRT_SECURE_NO_WARNINGS 1
#include"String.h"
int main()
{String str("Test string");for (String::iterator it = str.begin(); it != str.end(); ++it)cout << *it;cout << '\n';for (auto ch : str){cout << ch << " ";}cout << endl;return 0;
}

还有反向迭代器,这里就不一一列举了,想了解的可以参考string类的介绍

三  容量大小及操作

1.capacity()//表示容量大小

2.size()//有效数据大小

3.max_size()//最大有多少数据

4.empty()//是否为空

5.resize()//扩容

6.reserve()//扩容

size_t size()const{return _size;}size_t capacity()const{return _capacity;}size_t max_size()const{return 4294967291;}bool empty()const {return _size == 0;}void reserve(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){_str[n] = '\n';_size = n;}else{reserve(n);while (_size < n){_str[_size] = ch;_size++;}_str[_size] = '\0';}}

1.对于empty,它是如果为空,才是真,不为空就假

2.对于resize和reserve来说,从参数列表可以看出,resize可以设置初始值,也就是可以改变_size,

但是reserve不行,同时reserve设置的n如果比capacity小的话,是不会造成任何影响或者改变的

3.这里的max_size,这里我设置了一个常量,但是并没有这么简单,因为max_size是根据你当前系统来判断该给多大的,因素很多,但是实现起来很麻烦,这里就简单的设置为初始值了

测试案例

由于其他的测试在之前的string类博客测试过了,所以这里就不一一测试了

#define _CRT_SECURE_NO_WARNINGS 1
#include"String.h"
int main()
{String str("Test string");cout << "size: " << str.size() << "\n";cout << "capacity: " << str.capacity() << "\n";cout << "max_size: " << str.max_size() << "\n";return 0;
}

 

 四 运算符重载

 运算符重载就是>,<,=,>=,<=这四种,但是其实写一个大于和等于或者写一个小于和等于就行了,因为其他的都能复用

 4.1  bool operator<(const String& s) const
bool operator<(const String& s) const{return strcmp(_str, s._str) < 0;}

4.2  bool operator==(const String& s) const 
bool operator==(const String& s) const{return strcmp(_str, s._str) == 0;}

由于上面写了<和=的运算符重载,所以下面这几个直接复用前面的东西就行, 注意上面的写法用的是字符串函数进行比较,但是库里面用的是模板,所以这里有出入,如果用模板,就不能这样比较了

 4.3  bool operator<=(const String& s) const
bool operator<=(const String& s) const{return *this < s || *this == s;}
4.4 bool operator>(const String& s) const
bool operator>(const String& s) const{return !(*this <= s);}
4.5  bool operator>=(const String& s) const 
bool operator>=(const String& s) const{return !(*this < s);}
 4.6  bool operator!=(const String& s) const
bool operator!=(const String& s) const{return !(*this == s);}

 五  字符串操作 

5.1  截取操作

String substr(size_t pos = 0, size_t len = npos)const 

String substr(size_t pos = 0, size_t len = npos)const {assert(pos >= 0 && pos < _size);size_t end = len + pos;//最后的位置String s = "";if (len == npos || pos + len > _size)//如果长度已经大于当前字符串长度{len = _size - pos;//新长度就等于pos到_size这么长end = _size;//}s.reserse(len);//开辟空间for (int i = pos; i < end; i++)//从pos开始到end结束{s += _str[i];}return s;}

 测试样例:

5.2  查找操作

size_t find(char c, size_t pos = 0)const

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

查找一个字符 之间从pos位置开始遍历就行了

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

	size_t find(const char* s, size_t pos = 0)const{char* p = strstr(_str + pos, s);if (p){return p - _str;}else{return npos;}}

查找一个字符直接用库函数strstr就行 

测试用例: 

 

 

六  流插入流提取

由于这里的流插入和流提取不会涉及到私有的成员变量,所以不用写成友员函数

6.1  ostream& operator<<(ostream& out, const String& s)
ostream& operator<<(ostream& out, const String& s)
{for (auto ch : s){out << ch;}return out;
}
6.2   istream& operator>>(istream& in, String& s)
//流提取
istream& operator>> (istream& in, string& s)
{s.clear();char ch = in.get();while (ch != ' ' && ch != '\n'){s += ch;ch = in.get();}return in;
}

对于上面这段代码来说,我们首先要用一个clear去清理一下,因为不清理会导致之前的数据存在。

还有一点就是这段代码并不好,因为读字符的时候可能会导致频繁的扩容,我们电脑上面的程序可不止一个,不能一直中断其他程序,来进行这个,这样对于计算机的消耗有点大

istream& operator>>(istream& in, String& s)
{char buff[129];size_t i = 0;char ch;ch = in.get();while (ch != ' ' && ch != '\0'){buff[i++] = ch;if (i == 128){buff[i] = '\0';s += buff;i = 0;}ch = in.get();}if (i > 0){buff[i] = '\0';s += buff;}return in;
}

这段代码就是对之前的一个改良,设置一个数组去存, 当存到128个字符的时候再一起把它放进字符串里面去,最后还有判断一下如果i!=128的情况即可

 七  string与string相加

String operator+(const String& s2)

这里用成员函数来写,库里面用的是非成员函数

String operator+(const String& s2){String ret;ret._size = _size + s2._size;ret._str = new char[_capacity + s2._capacity];strcpy(ret._str, _str);strcpy(ret._str + _size, s2._str);return ret;}

先开空间,然后把两个字符串放进去就行。

string类模拟实现完整代码

#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
class String
{
public://迭代器typedef char* iterator;typedef 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(const char* str = "") :_size(strlen(str)), _capacity(_size){_str = new char[_capacity+1];strcpy(_str, str);}//析构函数~String(){delete[] _str;_str = nullptr;_size = 0;_capacity = 0;}//拷贝构造String(const String& s):_str(nullptr),_size(s._size), _capacity(s._capacity){_str = new char[_capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}//下表访问char& operator[](size_t pos){assert(pos < _size||pos>=0);return _str[pos];}void swap(String& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}//赋值运算符重载String&operator=(String tmp){swap(tmp);return *this;}//Capacitysize_t size()const{return _size;}size_t capacity()const{return _capacity;}size_t max_size()const{return 4294967291;}bool empty()const {return _size == 0;}void reserse(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){_str[n] = '\n';_size = n;}else{reserse(n);while (_size < n){_str[_size] = ch;_size++;}_str[_size] = '\0';}}//Element accesschar& back(){return _str[_size - 1];}const char& back()const{return _str[_size - 1];}char& front(){return _str[0];}const char& front()const {return _str[0];}//Modifiersvoid append(const char* str){size_t n = _size + strlen(str);if (n > _capacity){reserse(n);_capacity = n;}strcat(_str, str);_size += strlen(str);}void push_back(char ch){if (_size == _capacity){reserse(_capacity == 0 ? 4 : 2 * _capacity);}_str[_size] = ch;_size++;_str[_size] = '\0';}String& operator+=(const String& s){append(s._str);return *this;}String& operator+=(const char* str){append(str);return *this;}String& operator+=(char ch){push_back(ch);return *this;}void insert(size_t pos, char ch){assert(pos <= _size && pos >= 0);if (_size == _capacity){reserse(_capacity == 0 ? 4 : _capacity * 2);}size_t end = _size + 1;while (end > pos){_str[end] = _str[end-1];end--;}_str[pos] = ch;_size++;}void insert(size_t pos, const char* str){assert(pos <= _size && pos >= 0);int len = strlen(str);if (_size + len > _capacity){reserse(_size + len);}size_t end = _size+1;while (end > pos){_str[end + len] = _str[end-1];end--;}strncpy(_str + pos, str, len);_size += len;}void erase(size_t pos = 0, size_t len = npos){assert(pos >= 0 && pos < _size);if (len == npos||pos+len>_size){_str[pos] = '\0';_size = pos;}else{size_t end = pos + len;while (end <= _size){_str[end - len] = _str[end];end++;}_size -= len;}}//String operations:const char* c_str()const{return _str;}const char* data()const{return _str;}size_t find(char c, size_t pos = 0)const{for (int i = pos;i < _size; i++){if (_str[i] == c){return i;}}return npos;}size_t find(const char* s, size_t pos = 0)const{char* p = strstr(_str + pos, s);if (p){return p - _str;}else{return npos;}}String substr(size_t pos = 0, size_t len = npos)const {assert(pos >= 0 && pos < _size);size_t end = len + pos;String s = "";if (len == npos || pos + len > _size){len = _size - pos;end = _size;}s.reserse(len);for (int i = pos; i < end; i++){s += _str[i];}return s;}String operator+(const String& s2){String ret;ret._size = _size + s2._size;ret._str = new char[_capacity + s2._capacity];strcpy(ret._str, _str);strcpy(ret._str + _size, s2._str);return ret;}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);}
private:char* _str;size_t _size;size_t _capacity;static const size_t npos = -1;
};
//non_member constants
ostream& operator<<(ostream& out, const String& s)
{for (auto ch : s){out << ch;}return out;
}
istream& operator>>(istream& in, String& s)
{char buff[129];size_t i = 0;char ch;ch = in.get();while (ch != ' ' && ch != '\0'){buff[i++] = ch;if (i == 128){buff[i] = '\0';s += buff;i = 0;}ch = in.get();}if (i > 0){buff[i] = '\0';s += buff;}return in;
}

总结

以上就是string的全部内容了,💞。

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

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

相关文章

Unity【入门】脚本基础

Unity脚本基础 文章目录 1、脚本基本规则1、创建规则2、MonoBehavior基类3、不继承MonoBehavior的类4、执行的先后顺序5、默认脚本内容 2、生命周期函数1、概念2、生命周期函数有哪些3、生命周期函数支持继承多态 3、Inspector窗口可编辑的变量4、Mono中的重要内容1、重要成员2…

冯喜运:5.31晚间黄金原油行情分析及尾盘操作策略

【黄金消息面分析】&#xff1a;周五&#xff08;5月31日&#xff09;&#xff0c;最新发布的数据显示&#xff0c;美国4月核心PCE物价指数月率录得0.2%&#xff0c;低于预期(0.3%)&#xff0c;经济学家认为&#xff0c;核心指数比整体指数更能反映通胀。除此之外&#xff0c;美…

HackTheBox-Machines--Sense

Popcorn 测试过程 1 信息收集 服务器开启80、443端口 80端口 访问 80 跳转到 443 – https://10.129.196.51/ &#xff0c;该页面是 pfSense 登录界面&#xff0c;默认密码是&#xff1a; admin/pfSense&#xff0c;使用默认账号密码登录失败 目录扫描 ./gobuster dir -u htt…

深度神经网络——什么是线性回归?

线性回归是一种用于预测或可视化的算法 两个不同特征/变量之间的关系。 在线性回归任务中&#xff0c;要检查两种变量&#xff1a; 因变量和自变量。 自变量是独立的变量&#xff0c;不受其他变量的影响。 随着自变量的调整&#xff0c;因变量的水平将会波动。 因变量是正在研究…

三体中的冯诺依曼

你叫冯诺依曼&#xff0c;是一位科学家。你无法形容眼前的现态&#xff0c;你不知道下一次自己葬身火海会是多久&#xff0c;你也不知道会不会下一秒就会被冰封&#xff0c;你唯一知道的&#xff0c;就是自己那寥寥无几的科学知识&#xff0c;你可能会抱着他们终身&#xff0c;…

《QT实用小工具·六十九》基于QT开发的五子棋AI游戏

1、概述 源码放在文章末尾 该项目实现了五子棋对战AI&#xff0c;可以享受和AI下棋的快乐&#xff0c;项目实现思路如下&#xff1a; 博弈树 ●Alpha-Beta剪枝(性能提高较大) ●启发式搜索(性能提高较大) ●落子区域限制(性能提高较大) ●Zobrist哈希(性能小幅提升) ●Qt…

数据治理基础知识

文章目录 基本概念相关名词术语数据治理对象 基本概念 1&#xff09;从管理者视角看数据治理 数据治理是企业发展战略的组成部分&#xff0c;是指导整个集团进行数字化变革的基石&#xff0c;要将数据治理纳入企业的顶 层规划&#xff0c;各分/子公司、各业务部门都需要按照企…

软考高级系统规划与管理师适合什么人考?有什么优势?

系统规划与管理师适合什么人考&#xff1f; 适合以下几类人群&#xff1a; 1. 信息技术服务规划人员&#xff1a;从事信息技术服务规划工作&#xff0c;负责制定和优化IT服务规划的人 2. 信息系统运行维护管理人员&#xff1a;负责信息系统日常运行维护、确保系统稳定性和可…

【前端】Mac安装node14教程

在macOS上安装Node.js版本14.x的步骤如下&#xff1a; 打开终端。 使用Node Version Manager (nvm)安装Node.js。如果你还没有安装nvm&#xff0c;可以使用以下命令安装&#xff1a; curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash 然后关…

变压器励磁涌流MATLAB仿真模型

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 变压器励磁涌流的产生机理 1、变压器是电力系统的关键部分&#xff0c;在实际的 运行中&#xff0c;变压器需要进行相应的充电&#xff0c;而在充电的过 程中&#xff0c;就需要进行开合闸作业。在开合闸作业…

【Linux】磁盘结构文件系统软硬链接动静态库

目录 一.磁盘结构 1、磁盘的物理结构 2、磁盘的存储结构 3、磁盘的逻辑结构 二.文件系统 1、对IO单位的优化 2、磁盘分区与分组 3、对分组的具体管理方法 4、文件操作 三.软硬链接 1、理解硬链接 2、理解软连接 3、理解.和.. 四、动静态库 1、什么是动静态库 2、…

Flutter基础 -- Dart 语言 -- 基础类型

目录 0. 配置 1. 变量 1.1 弱类型 var Object dynamic 1.2 强类型 1.3 使用场景 var 简化定义变量 查询参数定义 返回的实例对象 2. 常量 final 和 const 2.1 相同点 类型声明可以省略 初始后不能再赋值 不能和 var 同时使用 2.2 不同点 const 需要确定的值 …

线性代数|机器学习-P1课程简介

文章目录 1. 书籍下载2. 正文 1. 书籍下载 链接&#xff1a;https://pan.baidu.com/s/1QbK0enLh0x4nU1c4Tqwlkw 提取码&#xff1a;r7ft 本课程回顾线性代数在概率论、统计学、优化和深度学习中的应用。是GILBERT STRANG教授的有一个经典的课程。课程将线性代数分为如下部分&a…

利用“记忆化搜索“解斐波那契数

一、题目描述 求第 n 个斐波那契数。 二、 利用"记忆化搜索"解斐波那契数 什么是记忆化搜索&#xff1f;记忆化搜索就是带有备忘录的递归。 我们先来看一下使用递归来解斐波那契数的这个过程&#xff0c;假设求第5个斐波那契数F(5)。 由图可见&#xff0c;要重复计…

Android加固多渠道打包和签名工具

简介 基于腾讯VasDolly最新版本3.0.6的图形界面衍生版本&#xff0c;同时增加了签名功能&#xff0c;旨在更好的帮助开发者构建多渠道包 使用说明 下载并解压最新工具包&#xff0c;找到Startup脚本并双击启动图形界面&#xff08;注意&#xff1a;需本地安装java环境&#…

手机定制开发_基于天玑900的5G安卓手机定制方案

手机定制方案基于联发科天玑900强劲旗舰八核2.4GHz处理器。这款处理器采用了6nm先进制程工艺&#xff0c;为用户带来了痛快淋漓的性能体验。不论是进行游戏还是日常娱乐&#xff0c;用户都能轻松驾驭。手机搭载了最新的Android 13操作系统&#xff0c;提高了数据读取的准确性&a…

小数第n位【蓝桥杯】

小数第n位 模拟 思路&#xff1a;arr数组用来记录已经出现过的a&#xff0c;在循环时及时退出。易知题目的3位即a%a后的第n-1,n,n1位。该代码非常巧妙&#xff0c;num记录3位的输出状况。 #include<iostream> #include<map> using namespace std; typedef long l…

vulnhub靶场之FunBox-9

一.环境搭建 1.靶场描述 Its a box for beginners, but not easy. Gather careful !!! Hint: Dont waste your time ! Every BruteForce-Attack at all ports can be stopped after 1500 trys per account. Enjoy the game and WYSIWYG ! This works better with VirtualBox…

博士毕业论文/CTEX/LATEX

LATEX环境安装 CTEX 安装 &#xff08;垃圾&#xff0c;不要装&#xff09; 运行 clean.batcomp.bat 缺少字体 Couldn’t find Adobe Heiti S.cfg’ miktex-maketfm: No creation rule for font “Adobe Heiti Std”.解决方法&#xff1a;其实就是下载这四个字体之后&…

【大比武10】行业垂直大模型应用在档案管理中的探索

关注我们 - 数字罗塞塔计划 - # 大比武2024 本篇是参加“华夏伟业”杯第二届档案信息化公司业务与技术实力大比武&#xff08;简称“大比武 2024”&#xff09;的投稿文章&#xff0c;来自广州龙建达电子股份有限公司&#xff0c;作者&#xff1a;陶宣任。 在这个人工智能技…