【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的全部内容了,💞。
相关文章:

【C++】——string模拟实现
前言 string的模拟实现其实就是增删改查,只不过加入了类的概念。 为了防止与std里面的string冲突,所以这里统一用String。 目录 前言 一 初始化和销毁 1.1 构造函数 1.2 析构函数 二 迭代器实现 三 容量大小及操作 四 运算符重载 4.1 bool…...

unity2D跑酷游戏
项目成果 项目网盘 导入资源包 放入Assets文件Assets资源文件 游戏流程分析 摄像机size调小,让图片占满屏幕 人跑本质,相对运动,图片无限向右滚动 图片720,缩小100倍第二个图片x为7.2每unit px100两张图片刚好挨着连贯 空对象Bg…...

OWASP top10--SQL注入(四、sqlmap安装及使用)
目录 sqlmap工具安装: 工具说明: 主要功能特性包括: 基本使用示例: 先下载python2.7.9版本 sqlmap运行 sqlmap工具使用 -u -r –-levelLEVEL扫描深度级别 --riskRISK 执行测试的风险 -threads 线程数 -batch-smart智能…...

Java基础入门day62
day62 AJAX 概念 AJAX: Asynchronous Javascript And XML AJAX是一种无需重新加载整个网页的情况下,能够更新部分网页的技术 AJAX是一种用于创建快速动态网页的技术 通过在后台与服务器进行少量数据交换,AJAX可以使网页实现异步更新 传统…...

Oracle中两张表具有相同结构,如何将一张表内容全部插入到另一个表中
在Oracle中,如果两张表具有相同的结构,你可以使用INSERT INTO ... SELECT语句将一张表的内容插入到另一张表中。以下是一个示例: 假设有两个表:table1 和 table2,它们具有相同的列结构。要将 table1 的所有内容插入到…...

比特币的理论上限是多少个?
标签: 比特币的理论上限; 已经挖出多少个比特币; 问题:比特币的理论上限是多少个?截至2023年10月,已经挖出多少个比特币出来了? 比特币的理论上限 比特币的设计者中本聪在比特币协议中设定了比…...

LeetCode-131 分割回文串
LeetCode-131 分割回文串 题目描述解题思路C 代码 题目描述 给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串。返回 s 所有可能的分割方案。 示例 1: 输入:s “aab” 输出:[[“a”,“a”,“b”],…...

Flutter 中的 SliverPrototypeExtentList 小部件:全面指南
Flutter 中的 SliverPrototypeExtentList 小部件:全面指南 Flutter 是一个功能强大的 UI 框架,由 Google 开发,允许开发者使用 Dart 语言构建跨平台的移动、Web 和桌面应用。在 Flutter 的丰富组件库中,SliverPrototypeExtentLis…...

NeuralForecast 推理 - 数据集从文件dataset.pkl读
NeuralForecast 推理 - 数据集从文件dataset.pkl读 flyfish from ray import tune from neuralforecast.core import NeuralForecast from neuralforecast.auto import AutoMLP from neuralforecast.models import NBEATS, NHITS import torch import torch.nn as nn import …...

TS-类型转换(显式)
1.将其他类型转换为布尔类型 要将其他类型转换为布尔类型,只需要将待转换的值传入Boolean()函数 var msg: string "ok"; var msgToBollean: boolean Boolean(msg); //得到trueBoolean()函数会判断传入的值是空值还是非空值。 若表示非空值࿰…...

protobufjs 配置踩坑记录
本文主要是小程序使用PB协议,以下时博主遇到的问题以及解决办法。 1、安装protobufjs npm install --save protobufjs 注意:我之前也使用过 npm install -g protobufjs去安装,但是出现以下的问题,关键是我使用sudo 清除相关文件…...

freeswitch官方仓库
概述 在使用源代码编译安装freeswitch的过程中,我们经常需要一些依赖库,其中freeswitch官方的yum源仓库是最齐全最方便的。 但是,freeswitch仓库的配置和使用需要先在signalwire网站注册账号并获取PAT(personal access token&am…...

element ui el-calendar日历组件完整代码
el-calendar日历组件完整代码 1. 说在前面2. 日历整体代码3. 编辑与新增 1. 说在前面 最近一直忙于上班,没咋看博客,发现很多小伙伴都要日历组件的代码,于是今天抽空给大家整理一下,为爱发电!日历组件的原文在这里&am…...

初识java——javaSE(8)异常
文章目录 一 异常的概念与体系结构1.1 什么是异常?1.2 异常的体系结构!1.3 编译时异常与运行时异常与Error编译时异常:异常声明:throws关键字 运行时异常:什么是Error? 二 处理异常2.1 异常的抛出:throw(注…...

C语言面试题11至20题
探索编程面试题:深度解析11至20题 在编程面试中,经常会遇到一些需要深入理解计算机科学基础和编程原理的问题。以下是对一些常见面试题的详细解答,涵盖递归、循环控制、内存管理等关键概念。 11. 递归函数定义没有问题,递归深层…...

视频汇聚EasyCVR综合安防平台对接GA/T1400公安视图库及应用方案
随着科技的不断进步,视频监控系统在公共安全领域发挥着越来越重要的作用。GA/T1400公安视图库作为公安视频图像信息应用系统的标准,为视频监控系统的对接提供了统一的规范和技术要求。 GA/T1400标准的应用范围广泛,涵盖了公安系统的视频图像信…...

在Github找自己想要的的项目
点击进入github 1.首先进入到github的首页;搜索框搜(先关键字搜索)in:name 你的找的项目 比如: in:name Sping Boot2.进一步检索(点赞数高的) in:name Sping Boot star:>1000 3.如何要找最新的&…...

第16篇:JTAG UART IP应用<三>
Q:如何通过HAL API函数库访问JTAG UART? A:Quartus硬件工程以及Platform Designer系统也和第一个Nios II工程--Hello_World的Quartus硬件工程一样。 Nios II软件工程对应的C程序调用HAL API函数,如open用于打开和创建文件&#…...

Python——Selenium快速上手+方法(一站式解决问题)
目录 前言 一、Selenium是什么 二、Python安装Selenium 1、安装Selenium第三方库 2、下载浏览器驱动 3、使用Python来打开浏览器 三、Selenium的初始化 四、Selenium获取网页元素 4.1、获取元素的实用方法 1、模糊匹配获取元素 & 联合多个样式 2、使用拉姆达表达式 3、加上…...

2024最新群智能优化算法:大甘蔗鼠算法(Greater Cane Rat Algorithm,GCRA)求解23个函数,提供MATLAB代码
一、大甘蔗鼠算法 大甘蔗鼠算法(Greater Cane Rat Algorithm,GCRA)由Jeffrey O. Agushaka等人于2024年提出,该算法模拟大甘蔗鼠的智能觅食行为。 参考文献 [1]Agushaka J O, Ezugwu A E, Saha A K, et al. Greater Cane Rat Alg…...

苍穹外卖数据可视化
文章目录 1、用户统计2、订单统计3、销量排名Top10 1、用户统计 所谓用户统计,实际上统计的是用户的数量。通过折线图来展示,上面这根蓝色线代表的是用户总量,下边这根绿色线代表的是新增用户数量,是具体到每一天。所以说用户统计…...

AWS需要实名吗?
AWS作为全球领先的云计算服务提供商,对于实名认证有着严格的要求。实名认证是指用户在使用AWS服务时需要提供真实有效的个人身份信息,以便AWS能够对用户的身份进行验证和管理。对于AWS而言,实名认证是确保用户安全和服务质量的重要环节&#…...

Android下HWC以及drm_hwcomposer普法(下)
Android下HWC以及drm_hwcomposer普法(下) 引言 不容易啊,写到这里。经过前面的普法(上),我相信童鞋们对HWC和drm_hwcomposer已经有了一定的认知了。谷歌出品,必须精品。我们前面的篇章见分析到啥来了,对了分析到了HwcDisplay::in…...

【评价类模型】熵权法
1.客观赋权法: 熵权法是一种客观求权重的方法,所有客观求权重的模型中都要有以下几步: 1.正向化处理: 极小型指标:取值越小越好的指标,例如错误率、缺陷率等。 中间项指标:取值在某个范围内较…...

PG 窗口函数
一,简介 窗口函数也叫分析函数,也叫OLAP函数,通过partition by分组,这里的窗口表示范围,,可以不指定PARATITION BY,会将这个表当成一个大窗口。 二,应用场景 (1)用于分…...

冯喜运:5.31晚间黄金原油行情分析及尾盘操作策略
【黄金消息面分析】:周五(5月31日),最新发布的数据显示,美国4月核心PCE物价指数月率录得0.2%,低于预期(0.3%),经济学家认为,核心指数比整体指数更能反映通胀。除此之外,美…...

Vue 框选区域放大(纯JavaScript实现)
需求:长按鼠标左键框选区域,松开后放大该区域,继续框选继续放大,反向框选恢复原始状态 实现思路:根据鼠标的落点,放大要显示的内容(内层盒子),然后利用水平偏移和垂直偏…...

C#加密与java 互通
文章目录 前言对方接口签名要求我方对接思路1.RSA 加密2.AES256加密 完整的加密帮助类 前言 提示:这里可以添加本文要记录的大概内容: 在我们对接其他公司接口的时候,时常会出现对方使用的开发语言和我方使用的开发语言不同的情况ÿ…...

C#【进阶】特殊语法
特殊语法、值和引用类型 特殊语法 文章目录 特殊语法1、var隐式类型2、设置对象初始值3、设置集合初始值4、匿名类型5、可空类型6、空合并操作符7、内插字符串8、单句逻辑简略写法 值和引用类型1、判断值和引用类型2、语句块3、变量的生命周期4、结构体中的值和引用5、类中的值…...

c语言之向文件读写数据块
c语言需要向文件读写数据块需要用到fread语句和fwrite语句 fread语句的语法格式 fread(butter,size,count,fp) butter:读取的数据存入内存地址 size:读取的字节大小 count:读取数据的个数 fp:读取的文件指针 fwrite语句语法格式 fwrite(butter,size,count,fp…...