当前位置: 首页 > news >正文

模拟实现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;}}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • C# 知识点总结
  • 前端了解到框架-网络复习
  • Unity Canvas动画:UI元素的动态展示
  • Angular 遍历列表时的key
  • Springboot集成Elasticsearch High Level REST Client实现增删改查实战
  • Gateway网关分布式微服务认证鉴权
  • 力扣高频SQL 50题(基础版)第二十五题
  • 基于PyCharm在Windows系统上远程连接Linux服务器中Docker容器进行Python项目开发与部署
  • react组件通信方式
  • 【简单介绍Gitea】
  • 记一次因为在html两个地方引入vue.js导致组件注入失败的问题
  • 算法基础课--学习--第一章
  • 深度学习:如何计算感受野
  • “微软蓝屏”事件,给IT行业带来的宝贵经验和教训
  • Leetcode49. 字母异位词分组(java实现)
  • 【EOS】Cleos基础
  • 【mysql】环境安装、服务启动、密码设置
  • 【跃迁之路】【519天】程序员高效学习方法论探索系列(实验阶段276-2018.07.09)...
  • 2018一半小结一波
  • 4月23日世界读书日 网络营销论坛推荐《正在爆发的营销革命》
  • Apache Spark Streaming 使用实例
  • conda常用的命令
  • Docker 笔记(1):介绍、镜像、容器及其基本操作
  • electron原来这么简单----打包你的react、VUE桌面应用程序
  • ES6核心特性
  • gulp 教程
  • iOS小技巧之UIImagePickerController实现头像选择
  • JavaScript设计模式与开发实践系列之策略模式
  • JSONP原理
  • js正则,这点儿就够用了
  • Python代码面试必读 - Data Structures and Algorithms in Python
  • 罗辑思维在全链路压测方面的实践和工作笔记
  • 免费小说阅读小程序
  • 目录与文件属性:编写ls
  • 使用前端开发工具包WijmoJS - 创建自定义DropDownTree控件(包含源代码)
  • 06-01 点餐小程序前台界面搭建
  • RDS-Mysql 物理备份恢复到本地数据库上
  • Semaphore
  • 不要一棍子打翻所有黑盒模型,其实可以让它们发挥作用 ...
  • 整理一些计算机基础知识!
  • #stm32整理(一)flash读写
  • #进阶:轻量级ORM框架Dapper的使用教程与原理详解
  • (6)【Python/机器学习/深度学习】Machine-Learning模型与算法应用—使用Adaboost建模及工作环境下的数据分析整理
  • (PHP)设置修改 Apache 文件根目录 (Document Root)(转帖)
  • (第30天)二叉树阶段总结
  • (分类)KNN算法- 参数调优
  • (附源码)计算机毕业设计ssm电影分享网站
  • (考研湖科大教书匠计算机网络)第一章概述-第五节1:计算机网络体系结构之分层思想和举例
  • (三)Pytorch快速搭建卷积神经网络模型实现手写数字识别(代码+详细注解)
  • (转)Android中使用ormlite实现持久化(一)--HelloOrmLite
  • (转)PlayerPrefs在Windows下存到哪里去了?
  • (转载)Linux 多线程条件变量同步
  • (轉貼) 寄發紅帖基本原則(教育部禮儀司頒布) (雜項)
  • .bat批处理(十一):替换字符串中包含百分号%的子串
  • .Net8 Blazor 尝鲜