模拟实现c++中的string

  c++内置string库的相关函数:string - C++ Reference

目录

一·string类构造,拷贝构造和析构:

二·string内正向迭代器实现:

三·赋值运算符重载实现:

四·reserve,empty,clear实现:

 五·push_back,append实现:

六·+=运算符实现:

七·swap和c_str()实现:

八·resize的实现:

九·比较关系的实现:

十·insert的实现:

十一·find的实现:

十二·erase的实现:

十三·substr的实现: 

十四· cin与cout实现:

十五·内部成员变量输出:

十六·访问操作符重载的实现:

总代码汇总:

string.h:

string.cpp:


一·string类构造,拷贝构造和析构:

  /// // //string 初始化://'\0'不占_capacity里的空间,但是它占空间,故开空间的时候给它开一个位置。而_capacity的大小//是有效元素占空间的大小。string(const char* str = "") {_size = strlen(str);_str = new char[_size + 1];_capacity = _size;strcpy(_str, str);}///拷贝构造: 如s1(s2)string(const string& s) {_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}
//析构函数:~string() {delete[]_str;_capacity = _size = 0;}

二·string内正向迭代器实现:

在这路可以把它看成指针来对其模拟操作:

 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;}

三·赋值运算符重载实现:

     //赋值重载: 如:s1=s1 s1=s2;(要把原先的数据和空间舍弃)string& operator=(const string& s) {if (strcmp(_str, s._str) == 0) {return *this;}else {clear();delete[]_str;_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;return *this;}}

四·reserve,empty,clear实现:

void string::reserve(size_t n) {if (n > _capacity) {char* tmp = new char[n + 1];strcpy(tmp, _str);delete[]_str;_str = tmp;_capacity = n;}}bool empty()const {return _size == 0;}
void string::clear() {_str[0] = '\0';_size = 0;}

 五·push_back,append实现:

void string::push_back(char c) {if (_size == _capacity) {reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size++] = c;_str[_size] = '\0';}void string::append(const char* str) {size_t len=strlen(str);if (_size == _capacity) {reserve(_size + len > _capacity * 2 ? _size + len : _capacity * 2);}strcpy(_str + _size, str);_size += len;}

六·+=运算符实现:

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

七·swap和c_str()实现:

	void  string:: swap(string& s) {//利用运算符重载出的赋值函数完成:string tmp = s;s = *this;*this = tmp;}const char* string::c_str()const {return this->_str;}

八·resize的实现:

void string::resize(size_t n, char c) {size_t i = 0;i = _size;if (n > _size) {if (n > _capacity) {reserve(n > 2 * _capacity ? n : 2 * _capacity);}size_t gap = n - _size;while (gap--) {_str[i++] = c;}}_str[i] = '\0';_size = i;}

九·比较关系的实现:

bool string:: operator<(const string& s) {return strcmp(_str, s._str)<0;}bool string:: operator==(const string& s) {return strcmp(_str, s._str) == 0;}bool string:: operator<=(const string& s) {return *this == s || *this < s;}bool string::operator>(const string& s) {return !(*this<=s);}bool string::operator>=(const string& s) {return *this == s || *this > s;}bool string:: operator!=(const string& s) {return !(*this == s);}

十·insert的实现:

string& string::insert(size_t pos, char c) {assert(pos < _size);if (_size + 1 > _capacity) {reserve(_size + 1 > 2 * _capacity ? _size + 1 : 2 * _capacity);}//保证内存空间最小也是数量的大小size_t end = _size;//从'\0'位置被覆盖即后挪。while (end > pos) {_str[end] = _str[end - 1];end--;}_str[pos] = c;_str[_size + 1] = '\0';//最后补充末尾的'\0'_size = _size + 1;return *this;}string& string::insert(size_t pos, const char* str) {assert(pos < _size);size_t len = strlen(str);if (_size + len > _capacity) {reserve(_size + len> 2 * _capacity ? _size + len : 2 * _capacity);}size_t end = _size+len-1;while (end >pos+len-1) {_str[end] = _str[end - len];end--;}//从'\0'开始移动,但是最后当拷贝过去'\0'会覆盖最后一个被移动的字符:char re = _str[pos + len];strcpy(_str + pos, str);_str[pos + len] = re;_str[_size + len] = '\0';_size = _size + len;return *this;}

十一·find的实现:

size_t string::find(char c, size_t pos ) const {assert(pos < _size);for (size_t i = pos; i <_size; i++) {if (_str[i] == c) {return i;}}return npos;}size_t string::find(const char* s, size_t pos) const {assert(pos < _size);const char *p=strstr(_str + pos, s);if (p == nullptr) {return npos;}else {return p - _str;}}

十二·erase的实现:

string& string::erase(size_t pos, size_t len) {assert(pos < _size);//len长于pos后面的位置,直接都删。if (pos + len > _size) {_str[pos] = '\0';_size = pos;}//否则把len后面的字符串copy到pos位置。else {strcpy(_str + pos, _str +pos+ len);_size = _size - len;}return *this;}

十三·substr的实现: 

	string string::substr(size_t pos, size_t len) {assert(pos < _size);if (len == npos) {len = _size - pos;//实际长度}string tmp;for (size_t i = pos; len>0; i++,len--) {tmp += _str[i];}return tmp;}

十四· cin与cout实现:

由于默认第一个参数是this问题,把它定义在外部作为友好函数去访问内部成员:

 ostream& operator<<(ostream& _cout, const st::string& s){for (auto ch : s){_cout << ch;}return _cout;}//istream& operator>>(istream& _cin, st::string& s);istream& operator>>(istream& _cin, st::string& s) {if (!s.empty()) {s.clear();}char buff[2024] = { 0 };//利用数组,先把输入的元素放入栈的数组里,//快满了后追加到string的数组里,方便对开空间的掌握,以及减少调用reserve函数次数char ch = _cin.get();//输入到缓冲区,只要有字符就读取,没有get()就先输入在读取int i = 0;while(ch!=' '&&ch!='\n') {buff[i++] = ch;if (i == 2023) {s += buff;i = 0;}ch = _cin.get();}if (i != 0) {s += buff;}return _cin;}

十五·内部成员变量输出:

   size_t size()const {return _size;}size_t capacity()const {return _capacity;}bool empty()const {return _size == 0;}

十六·访问操作符重载的实现:

//获取指定字符:char& operator[](size_t index) {assert(index < _size);return _str[index];}const char& operator[](size_t index)const {assert(index < _size);return _str[index];}//不可修改的访问,//如:const st::string s3("xyz");//s3[1] = 1;
//定义的const对象,其成员都不能被修改,就自动调用const类的

十七·对swap,拷贝构造,赋值的现代写法:

首先它并没有多大的提高效率,而是可以这么理解:它会让我们手动自行的操作减少一部分,通过调用如实现创造好的swap。比如:这个自己写的swap与std里的swap 有所不同,大概就是库里用的模版出的类,会有空间反复开辟,而自己写的这个直接交换指针就好,那么就相当于指向的空间就也互换了。

   ///swap现代写法:(不用开辟对象,仅仅做到成员交换,让它们指向的空间互换即可)void swap(string& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}

对拷贝构造而言:如:s1拷给s2

可以不在里面自己手写成员赋值等,调用构造+swap即可(但是这里如果一开始s1被插入过数据,扩过容,_capacity可能不一):

 string(const string&s) {string tmp(s._str);swap(tmp);}

对于赋值操作,可以分为两种:如:s1=s2;第一种就是不改变s2的前提下完成:

  //不改变s2情况下:string& operator =(const string& s ) {if (*this != s) {string tmp(s._str);swap(tmp);}return* this;}

第二种就是改变了s2,把s1的资源给了它:

 string& operator =(string& s) {swap(s);return*this;}

 

 

总代码汇总(传统写法):

string.h:

#pragma once#include<iostream>
#include<assert.h>using namespace std;
namespace st{class string{friend ostream& operator<<(ostream& _cout, const st::string& s);friend istream& operator>>(istream& _cin, st::string& s);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 初始化://'\0'不占_capacity里的空间,但是它占空间,故开空间的时候给它开一个位置。而_capacity的大小//是有效元素占空间的大小。string(const char* str = "") {_size = strlen(str);_str = new char[_size + 1];_capacity = _size;strcpy(_str, str);}///拷贝构造: 如s1(s2)string(const string& s) {_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}//赋值重载: 如:s1=s1 s1=s2;(要把原先的数据和空间舍弃)string& operator=(const string& s) {if (strcmp(_str, s._str) == 0) {return *this;}else {clear();delete[]_str;_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;return *this;}}//清除数据,改size但容量不变:void clear();//析构函数:~string() {delete[]_str;_capacity = _size = 0;}void push_back(char c);string& operator+=(char c);void append(const char* str);string& operator+=(const char* str);void swap(string& s);const char* c_str()const;///capacitysize_t size()const {return _size;}size_t capacity()const {return _capacity;}bool empty()const {return _size == 0;}//增大尺寸:void resize(size_t n, char c = '\0');//预存空间/扩容:void reserve(size_t n);//////获取指定字符:char& operator[](size_t index) {assert(index < _size);return _str[index];}const char& operator[](size_t index)const {assert(index < _size);return _str[index];}///relational operators:bool operator<(const string& s);bool operator<=(const string& s);bool operator>(const string& s);bool operator>=(const string& s);bool operator==(const string& s);bool operator!=(const string& s);返回c在string中第一次出现的位置size_t find(char c, size_t pos = 0) const;返回子串s在string中第一次出现的位置size_t find(const char* s, size_t pos = 0) const;在pos位置上插入字符c/字符串str,并返回该字符的位置string& insert(size_t pos, char c);string& insert(size_t pos, const char* str);删除pos位置上的元素,并返回该元素的下一个位置string& erase(size_t pos, size_t len);//从指定位置往后找len个长度子串并返回string类型对象string substr(size_t pos, size_t len = npos);private:char* _str;size_t _capacity;size_t _size;static const size_t  npos;};}

string.cpp:

#define _CRT_SECURE_NO_WARNINGS
#include"string.h"namespace st {const size_t  string::npos = -1;void string::clear() {_str[0] = '\0';_size = 0;}void string::push_back(char c) {if (_size == _capacity) {reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size++] = c;_str[_size] = '\0';}void string::reserve(size_t n) {if (n > _capacity) {char* tmp = new char[n + 1];strcpy(tmp, _str);delete[]_str;_str = tmp;_capacity = n;}}string& string::operator+=(char c) {push_back(c);return *this;}void string::append(const char* str) {size_t len=strlen(str);if (_size == _capacity) {reserve(_size + len > _capacity * 2 ? _size + len : _capacity * 2);}strcpy(_str + _size, str);_size += len;}string& string:: operator+=(const char* str) {append(str);return *this;}void  string:: swap(string& s) {//利用运算符重载出的赋值函数完成:string tmp = s;s = *this;*this = tmp;}const char* string::c_str()const {return this->_str;}void string::resize(size_t n, char c) {size_t i = 0;i = _size;if (n > _size) {if (n > _capacity) {reserve(n > 2 * _capacity ? n : 2 * _capacity);}size_t gap = n - _size;while (gap--) {_str[i++] = c;}}_str[i] = '\0';_size = i;}bool string:: operator<(const string& s) {return strcmp(_str, s._str)<0;}bool string:: operator==(const string& s) {return strcmp(_str, s._str) == 0;}bool string:: operator<=(const string& s) {return *this == s || *this < s;}bool string::operator>(const string& s) {return !(*this<=s);}bool string::operator>=(const string& s) {return *this == s || *this > s;}bool string:: operator!=(const string& s) {return !(*this == s);}string& string::insert(size_t pos, char c) {assert(pos < _size);if (_size + 1 > _capacity) {reserve(_size + 1 > 2 * _capacity ? _size + 1 : 2 * _capacity);}//保证内存空间最小也是数量的大小size_t end = _size;//从'\0'位置被覆盖即后挪。while (end > pos) {_str[end] = _str[end - 1];end--;}_str[pos] = c;_str[_size + 1] = '\0';//最后补充末尾的'\0'_size = _size + 1;return *this;}string& string::insert(size_t pos, const char* str) {assert(pos < _size);size_t len = strlen(str);if (_size + len > _capacity) {reserve(_size + len> 2 * _capacity ? _size + len : 2 * _capacity);}size_t end = _size+len-1;while (end >pos+len-1) {_str[end] = _str[end - len];end--;}//从'\0'开始移动,但是最后当拷贝过去'\0'会覆盖最后一个被移动的字符:char re = _str[pos + len];strcpy(_str + pos, str);_str[pos + len] = re;_str[_size + len] = '\0';_size = _size + len;return *this;}size_t string::find(char c, size_t pos ) const {assert(pos < _size);for (size_t i = pos; i <_size; i++) {if (_str[i] == c) {return i;}}return npos;}size_t string::find(const char* s, size_t pos) const {assert(pos < _size);const char *p=strstr(_str + pos, s);if (p == nullptr) {return npos;}else {return p - _str;}}string& string::erase(size_t pos, size_t len) {assert(pos < _size);//len长于pos后面的位置,直接都删。if (pos + len > _size) {_str[pos] = '\0';_size = pos;}//否则把len后面的字符串copy到pos位置。else {strcpy(_str + pos, _str +pos+ len);_size = _size - len;}return *this;}string string::substr(size_t pos, size_t len) {assert(pos < _size);if (len == npos) {len = _size - pos;//实际长度}string tmp;for (size_t i = pos; len>0; i++,len--) {tmp += _str[i];}return tmp;}ostream& operator<<(ostream& _cout, const st::string& s){for (auto ch : s){_cout << ch;}return _cout;}//istream& operator>>(istream& _cin, st::string& s);istream& operator>>(istream& _cin, st::string& s) {if (!s.empty()) {s.clear();}char buff[2024] = { 0 };//利用数组,先把输入的元素放入栈的数组里,//快满了后追加到string的数组里,方便对开空间的掌握,以及减少调用reserve函数次数char ch = _cin.get();//输入到缓冲区,只要有字符就读取,没有get()就先输入在读取int i = 0;while(ch!=' '&&ch!='\n') {buff[i++] = ch;if (i == 2023) {s += buff;i = 0;}ch = _cin.get();}if (i != 0) {s += buff;}return _cin;}}

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

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

相关文章

动手学深度学习——6.循环神经网络

1.序列模型 处理序列数据需要统计工具和新的深度神经网络架构。 为了简单起见&#xff0c;我们以 图8.1.1所示的股票价格&#xff08;富时100指数&#xff09;为例。 图8.1.1 近30年的富时100指数 其中&#xff0c;用&#x1d465;&#x1d461;表示价格&#xff0c;即在时间…

LIS检验信息软件源码,适合二级医院的应用

LIS系统主要面向医院检验科&#xff0c;包含检验医生日常处理、报告处理、质量控制、条码管理、仪器双工通讯、无人值守等诸多功能模块&#xff0c;能与HIS系统、体检系统和电子病历信息系统实现无缝连接&#xff0c;已成功应用于多家各种规模的医院&#xff0c;满足客户各方面…

Git之repo sync -c与repo sync -dc用法区别(四十八)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

InternLM学习笔记

入门岛 1. Linux基础知识 2. Python 基础知识 from collections import Countertext """ Got this panda plush toy for my daughters birthday, who loves it and takes it everywhere. Its soft and super cute, and its face has a friendly look. Its a …

论文阅读【检测】:Facebook ECCV2020 | DETR

文章目录 论文地址AbstractMotivation模型框架详细结构小结 论文地址 DETR Abstract 提出了一种将目标检测视为直接集预测问题的新方法。简化了检测pipeline&#xff0c;有效地消除了许多手工设计的组件的需求&#xff0c;例如非最大抑制过程或锚生成&#xff0c;这些组件明…

设计模式|观察者模式

观察者模式是一种行为设计模式&#xff0c;它定义了一种一对多的依赖关系&#xff0c;让多个观察者对象同时监听某一个主题对象。当主题对象发生变化时&#xff0c;它的所有观察者都会收到通知并更新。观察者模式常用于实现事件处理系统、发布-订阅模式等。在项目中&#xff0c…

磁盘管理与磁盘卷--红帽Linux操作系统<>

分区的两种格式 1、MBR分区 MBR(Master Boot Record&#xff0c;主引导记录)是传统的分区机制&#xff0c;使用BI0S引导PC设备&#xff0c;寻址空间只有32bit长。 分区空间最大支持2.2TB 支持的分区数量:4个主分区或者3个主分区1个扩展分区 为什么MBR最多只能有4个主分区?…

云服务部署项目(Spring + Vue)

云计算&#xff1a;腾讯云 操作系统&#xff1a;Ubuntu 22.04.4 LTS 项目&#xff1a;若依前后端分离项目&#xff08;SpringBoot Vue&#xff09; 首先要安装基本的一些依赖环境&#xff0c;大家可以看一下我往期的文章&#xff1a; Ubuntu在线JDK Ubuntu在线安装Nginx Ubunt…

文件解析的终极工具:Apache Tika

文件解析的终极工具&#xff1a;Apache Tika Apache Tika 简介 Apache Tika 是一个开源的、跨平台的库&#xff0c;用于检测、提取和解析各种类型文件的元数据。 它支持多种文件格式&#xff0c;包括文档、图片、音频和视频。 Tika是一个底层库&#xff0c;经常用于搜索引擎…

Android 列表或网格形式展示大量数据:RecyclerView

目录 RecyclerView是什么如何使用RecyclerView 涉及到的类LayoutManager为Item设置不同的布局样式制作拖动的RecyclerView 一、RecyclerView是什么 RecyclerView是Android支持库中的一个控件&#xff0c;用于在列表或网格形式展示大量数据。它是ListView的升级版&#xff0c…

《梦醒蝶飞:释放Excel函数与公式的力量》18.1 图表类型与设计

第18章&#xff1a;创建图表和数据可视化 18.1 图表类型与设计 Excel提供了多种图表类型&#xff0c;帮助用户以直观的方式展示数据。选择合适的图表类型和设计可以显著提高数据的可读性和理解度。以下将介绍常见的图表类型及其应用&#xff0c;并通过具体案例进行说明。 18.…

如何利用Jenkins自动化管理、部署数百个应用

目录 1. Jenkins 安装与部署步骤 1.1 系统要求 1.2 安装步骤 1.2.1 Windows 系统 1.2.2 CentOS 系统 1.3 初次配置 2. Gradle 详细配置方式 2.1 安装 Gradle 2.1.1 Windows 系统 2.1.2 CentOS 系统 2.2 配置 Jenkins 中的 Gradle 3. JDK 详细配置方式 3.1 安装 JD…

Java:防止输入输出超时

一、防止输入超时 当我们直接使用Scanner进行输入操作的时候&#xff0c;每次读取输入的数据都会进行一次硬盘的IO操作&#xff0c;这个操作是很慢的&#xff0c;如果要读取的数据过多&#xff0c;那么我们在刷题网站上就很有可能因为多次的数据读取操作产生超时&#xff01;那…

渠道查问卷调查个人怎么做?

大家好&#xff0c;我是橙河老师&#xff0c;今天讲一讲渠道查问卷调查个人怎么做&#xff1f; 对海外问卷项目有过一些了解的人呢&#xff0c;都应该知道一些渠道查的优势&#xff0c;首先是省去了注册账号、养号一系列的繁琐操作&#xff0c;那通过测题、做题&#xff0c;然…

vscode调试nextjs前端后端程序、nextjs api接口

最近有一个项目使用了nextjs框架&#xff0c;并且使用nextjs同时实现了前后端&#xff0c;由于之前前后端都是分离的&#xff0c;前端的调试可以通过在代码种添加debugger或者直接在浏览器中打断点实现&#xff0c;现在想调试后端接口&#xff0c;前面的方式就不适用了。故研究…

CMA软件实验室评审如何做好人员技术能力的评价?

人员作为实验室的一个重要质量因素&#xff0c;其技术能力和素质水平体现了实验室水平的高低。人员能力是随着时间动态变化的&#xff0c;有效地评价实验室人员的技术能力&#xff0c;是保证实验室活动的必要条件。CMA软件实验室评审也要求实验室要注意对人员能力的监督&#x…

基于web的物流配送管理系统/基于客户时间窗变化的物流配送管理系统/快递配送管理系统

摘 要 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;各行各业相继进入信息管理时代&a…

性能测试工具、负载测试工具、缺陷跟踪工具推荐

负载测试工具 - 有助于对站点或应用程序进行性能/负载测试 1&#xff09;WebLOAD WebLOAD 是一款出色的测试工具&#xff0c;提供了许多强大的脚本功能&#xff0c;有助于测试复杂场景。该工具支持从 Selenium 到移动端、从企业应用到网络协议的数百种技术。使用这款工具可以…

JAVA.包、final、权限

包 final 权限 代码块 1.构造代码块 创建这个本类的对象的时候会先指向构造代码块再执行构造方法 作用&#xff1a;把构造方法重复的部分抽取出来 2.静态代码块 static 随着类的加载而加载&#xff0c;只执行一次。 作用&#xff1a;数据初始化&#xff0c;比如在学生管…

CSS学习笔记[Web开发]

CSS学习 本文为学习笔记&#xff0c;参考菜鸟和w3c 文章目录 CSS 简介CSS 插入外部 CSS内部 CSS行内 CSS多个样式表层叠顺序 CSS 语法例子解释 CSS 选择器CSS 元素选择器CSS id 选择器实例CSS 类选择器实例CSS 通用选择器实例CSS 分组选择器CSS 后代选择器CSS 子元素选择器CSS …