C++ string类模拟实现

文章目录

  • 构造函数
  • 拷贝构造函数
  • 析构
  • 流插入<<
  • 流提取>>
  • =
  • begin()
  • end()
  • []
  • find()
  • insert()
  • push_back()
  • appned()
  • +=
  • c_str()
  • 获取私有成员变量
  • resize()
  • reserve()
  • <
  • erase()
  • 完整代码

构造函数

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

这个构造函数有两种形式,当没有参数时,以空字符串" "为默认值,带参时则用str初始化字符串。

拷贝构造函数

     string(const string& s):_size(s._size),_capacity(s._capacity){_str = new char[s._capacity + 1];strcpy(_str, s._str);}

这个构造函数接受一个string类的引用s作为参数,并基于这个引用创建一个新的string对象。

析构

   ~string(){delete[] _str;_str = nullptr;_capacity = _size = 0;}

流插入<<

  friend ostream& operator<<(ostream& _cout,const bit::string& s){         for (auto ch : s){_cout << ch;}return _cout;           }

这段代码定义了一个重载的operator<<函数,ostream&: 表示这个函数返回一个ostream类型的引用,它允许operator<<能够链式调用。
友元函数使函数能在类外面调用私有成员变量,也可以通过getxxx()函数来调用。

流提取>>

      friend istream& operator>>(istream& _cin, string& s){s.clear();char ch;// 定义一个字符变量用于临时存储从输入流读取的字符 ch = cin.get();char buff[128];size_t i = 0;while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == 127){buff[127] = '\0';s += buff;i = 0;}ch = cin.get();}// 如果 buff 数组中有剩余字符(即 i > 0),则将它们附加到 s 中if (i > 0){buff[i] = '\0';s += buff;}return cin;}

这里定义了一个缓冲数组buff来获取输入的字符,数组buff在创建时就被分配内存,并在整个使用过程中被重用,这样可以减少动态分配和回收内存的次数,提高了性能。

=

string& operator=(const string& s){char* tmp=new char[s._capacity + 1];strcpy(tmp, s._str);delete[] _str;_str = tmp;_capacity = s._capacity;_size = s._size;return *this;}

这是一个赋值操作符的重载,利用tmp将s字符串的内容保存,再重新分配_str的指向,完成字符串内容的复制。

begin()

typedef char* iterator;iterator begin()const{return _str;}

_str 是存储字符串内容的字符数组的起始地址。

end()

  iterator end()const{return _str+_size;}

首地址加字符数组长度等于尾地址。

[]

    char& operator[](size_t index){assert(index < _size);return _str[index];
}const char& operator[](size_t index)const{assert(index < _size);return _str[index];}

find()

      size_t find(char c, size_t pos = 0) const{while (_str[pos] != c&&pos<_size){pos++;}if (pos >= _size)return -1;return pos;}size_t find(const char* s, size_t pos = 0) const{assert(pos < _size);const char* p = strstr(_str + pos, s);if (p){return p - _str;}else{return -1;}
}

第一个find()函数用于在字符串中查找指定字符 c 的位置,找到则返回元素c的位置pos,否则返回-1.
第二个find()函数用于在字符串中查找子字符串 s 的位置,strstr 函数简化了子字符串的查找过程。

insert()

       string& insert(size_t pos, char c){assert(pos <= _size);if (_size == _capacity){reserve(_capacity == 0 ? 4 : 2 * _capacity);}size_t end = _size + 1;while (end > pos){_str[end] = _str[end - 1];--end;}_str[pos] = c;++_size;return *this;}string& insert(size_t pos, const char* str){assert(pos <= _size);if (_size >= _capacity){reserve(_capacity == 0 ? 4 : 2 * _capacity);}int len = strlen(str);size_t end = _size + len;while (end > pos + len-1){_str[end] = _str[end - len];--end;}strncpy(_str + pos, str, len);_size += len;return *this;}

这两段代码定义了一个字符串类中的 insert 成员函数,用于在字符串的指定位置插入一个字符或子字符串。assert确保插入位置pos的合法性,第二个函数的循环将 pos + len 位置及其之后的所有字符向后移动 len 个位置,以便为子字符串腾出空间。最后都返回对当前字符串的引用。

push_back()

 void push_back(char c){insert(_size, c);}

appned()

   void append(const char* str){insert(_size, str);}

appned()函数是在末尾插入字符串,利用模拟的insert来实现

+=

   string& operator+=(char c){push_back(c);return *this;}//单子符string& operator+=(const char* str){append(str);return *this;}//字符串

c_str()

 const char* c_str()const{return _str;}

获取私有成员变量

size_t size()const{return _size;}size_t capacity()const{return _capacity;}

resize()

      void resize(size_t n, char c = '\0'){if(n>_size){while(_size<n){reserve(n);_str += c;_size++;}}else if(n<_size){_str[n] = '\0';_size = n;}}

resize函数的主要作用是调整容器或数据的大小,在这也就是改变_size的大小,当n小于_size时,将_size减小到n并在新串末尾加上终止字符,当n大于_size时,先用reserve()开辟足够的空间,再填补字符c。

reserve()

      void reserve(size_t n){if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}}

reserve函数用于改变容器(如vector)的容量,这里只用判断当n大于原来的容量_capacity时,开辟足够大的空间。

<

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

erase()

    string& erase(size_t pos, size_t len){assert(pos < _size);if (len == std::string::npos || len >= _size - pos){_str[pos] = '\0';_size = pos;}else{strcpy(_str + pos, _str + pos + len);_size -= len;}return *this;
}

erase 函数用于从自定义字符串类的一个实例中删除从指定位置 pos 开始的 len 个字符。

完整代码

#define _CRT_SECURE_NO_WARNINGS 1.
#pragma once
#include<iostream>
#include<assert.h>
#include<string>
using namespace std;namespace bit{class string{friend ostream& operator<<(ostream& _cout,const bit::string& s){         for (auto ch : s){_cout << ch;}return _cout;           }friend istream& operator>>(istream& _cin, string& s){s.clear();char ch;ch = cin.get();char buff[128];size_t i = 0;while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == 127){buff[127] = '\0';s += buff;i = 0;}ch = cin.get();}if (i > 0){buff[i] = '\0';s += buff;}return cin;}public:typedef char* iterator;public:string(const char* str = ""):_size(strlen(str)){_str = new char[strlen(str)+1];strcpy(_str, str);_capacity = _size;}string(const string& s):_size(s._size),_capacity(s._capacity){_str = new char[s._capacity + 1];strcpy(_str, s._str);}string& operator=(const string& s){char* tmp=new char[s._capacity + 1];strcpy(tmp, s._str);delete[] _str;_str = tmp;_capacity = s._capacity;_size = s._size;return *this;}~string(){delete[] _str;_str = nullptr;_capacity = _size = 0;}//// iteratoriterator begin()const{return _str;}iterator end()const{return _str+_size;}/// modifyvoid push_back(char c){/* if (_size == _capacity){reserve(_capacity == 0 ? 4 : 2 * _capacity);}_str[_size++] = c;_str[_size] = '\0';*/insert(_size, c);}string& operator+=(char c){push_back(c);return *this;}void append(const char* str){/*  size_t len = strlen(str);if (_size > _capacity - len){reserve(_size+len);}strcpy(_str + _size, str);_size += len;*/insert(_size, str);}string& operator+=(const char* str){append(str);return *this;}void clear(){delete[] _str;_str = nullptr;_capacity = _size = 0;}void swap(string& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}const char* c_str()const{return _str;}/// capacitysize_t size()const{return _size;}size_t capacity()const{return _capacity;}bool empty()const{return _capacity == 0;}void resize(size_t n, char c = '\0'){if(n>_size){while(_size<n){reserve(n);_str += c;_size++;}}else if(n<_size){_str[n] = '\0';_size = n;}}void reserve(size_t n){if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}}/// accesschar& operator[](size_t index){assert(index < _size);return _str[index];}const char& operator[](size_t index)const{assert(index < _size);return _str[index];}///relational operatorsbool operator<(const string& s){return strcmp(_str, s._str) < 0;}bool operator<=(const string& s){return !(_str > s._str);}bool operator>(const string& s){return strcmp(_str, s._str) > 0;}bool operator>=(const string& s){return !(_str < s._str);}bool operator==(const string& s){return strcmp(_str, s._str)==0;}bool operator!=(const string& s){return !(_str == s._str);}// 返回c在string中第一次出现的位置size_t find(char c, size_t pos = 0) const{while (_str[pos] != c&&pos<_size){pos++;}if (pos >= _size)return -1;return pos;}// 返回子串s在string中第一次出现的位置size_t find(const char* s, size_t pos = 0) const{assert(pos < _size);const char* p = strstr(_str + pos, s);if (p){return p - _str;}else{return -1;}}// 在pos位置上插入字符c/字符串str,并返回该字符的位置string& insert(size_t pos, char c){assert(pos <= _size);if (_size == _capacity){reserve(_capacity == 0 ? 4 : 2 * _capacity);}size_t end = _size + 1;while (end > pos){_str[end] = _str[end - 1];--end;}_str[pos] = c;++_size;return *this;}string& insert(size_t pos, const char* str){assert(pos <= _size);if (_size >= _capacity){reserve(_capacity == 0 ? 4 : 2 * _capacity);}int len = strlen(str);size_t end = _size + len;while (end > pos + len-1){_str[end] = _str[end - len];--end;}strncpy(_str + pos, str, len);_size += len;return *this;}// 删除pos位置上的元素,并返回该元素的下一个位置string& erase(size_t pos, size_t len){assert(pos < _size);if (len == std::string::npos || len >= _size - pos){_str[pos] = '\0';_size = pos;}else{strcpy(_str + pos, _str + pos + len);_size -= len;}return *this;}private:char* _str=nullptr;size_t _capacity=0;size_t _size=0;};}

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

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

相关文章

牛客周赛 31

牛客周赛 Round 31 文章目录 牛客周赛 Round 31A 小红小紫替换B 小红的因子数C 小红的字符串中值D 小红数组操作E 小红的子集取反 A 小红小紫替换 语法 #include <bits/stdc.h>using namespace std;int main() {string s;cin >> s;if(s "kou"){cout &…

C# Path 类

在 C# 中&#xff0c;Path 类位于 System.IO 命名空间中&#xff0c;提供了一组用于操作和处理文件路径的静态方法。Path 类可以用于处理文件名、目录名和路径等相关操作。 下面是一些 Path 类常用的方法和示例说明&#xff1a; Path.Combine&#xff1a;用于组合多个字符串片…

docker开机启动设置

添加开机启动 # 添加开机启动配置 sudo vim /usr/lib/systemd/system/docker.service 文件内容 [Unit] DescriptionDocker Application Container Engine Documentationhttps://docs.docker.com Afternetwork-online.target firewalld.service Wantsnetwork-online.target […

【ros2 control 机器人驱动开发】双关节多控制器机器人学习-example 6

【ros2 control 机器人驱动开发】双关节多控制器机器人学习-example 6 文章目录 前言一、创建controller相关二、逻辑分析RRBotModularJoint类解析ros2_control.xacro解析三、测试运行测试forward_position_controller总结前言 本篇文章在上篇文章的基础上主要讲解双轴机器人驱…

uView Subsection 分段器

该分段器一般用于用户从几个选项中选择某一个的场景 #平台差异说明 App&#xff08;vue&#xff09;App&#xff08;nvue&#xff09;H5小程序√√√√ #基本使用 通过list数组参数传递分段的选项&#xff0c;数组元素可为字符串&#xff0c;或者通过keyName参数传入对象(默…

你真的用对了知识管理系统了吗?这篇文章教会你

面对信息化社会的信息爆炸&#xff0c;知识管理系统如同一艘救生船&#xff0c;帮助我们捕捉、储存、共享重要的知识&#xff0c;并提高工作效率。但是&#xff0c;你真的用对了知识管理系统吗&#xff1f;让这篇文章成为你的参考指南。 了解知识管理系统的功能导则 首先&…

数据通信练习题

1.0osi七层模型 应用层 data 表示层 会话层 传输层 数据段 防火墙&#xff0c;端口&#xff08;TCP UDP&#xff09; 网络层 数据包 路由器 数据链路层 数据帧 交换机 物理层 比特流 网卡 2.IP地址分类 私有地址 A类 0--127 10.0.0.0…

vue学习笔记23-组件事件⭐

组件事件 在组件的模板表达式中&#xff0c;可以直接使用$emit方法触发自定义事件&#xff1b;触发自定义事件的目的是组件之间传递数据 好好好今天又碰到问题了&#xff0c;来吧来吧 测试发现其他项目都可以 正常的run ,就它不行 搜索发现新建项目并进入以后&#xff0c;用指…

数据结构->双向链表带你体验开火车(哨兵)与拼接火车(应用)厢的乐趣

✅作者简介&#xff1a;大家好&#xff0c;我是橘橙黄又青&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;橘橙黄又青-CSDN博客 目的&#xff1a;学习双向带头链表的增&#xff0c;删&#xff0c;查&#xff0c;销毁…

代码随想录算法训练营第41天|背包理论基础 滚动数组法 416.分割等和子集

背包理论基础 终于开始刷大名鼎鼎的背包问题了&#xff0c;背包问题有点复杂&#xff0c;我还是懂了但没完全懂&#xff0c;下面是我现在的理解&#xff0c;我们把dp[i][j]定义为i个物品在背包容量为j下的价值&#xff0c;那么这样就转换为如果要求价值&#xff0c;这个价值和前…

链表——单链表的C实现(保姆级代码、注释教学)

首先需要借助三个文件 SList.h SList.c test.c 目录 SList.h &#xff1a;用来建立结构体、头文件、函数声明、全局变量建立 SList.c&#xff1a;对头文件中声明的函数的实现 void SLTPrint(SLTNode* phead) SLTNode* BuyLTNode(SLTDataType x) voi…

《软件项目管理:从规划到实施的全面指南》

软件项目管理是当今信息技术领域中至关重要的一环。在一个数字化、信息化的时代&#xff0c;几乎所有行业都依赖于软件来支撑其业务流程和运营。然而&#xff0c;软件开发过程往往是复杂的&#xff0c;充满了挑战和风险。为了确保软件项目能够按时交付、在预算范围内完成&#…

『大模型笔记』大模型中的Scaling Law(规模法则)

大模型中的Scaling Law(规模法则) 文章目录 一. 核心结论二. 大模型中的Scaling Law三. 参考文献Scaling Laws简单介绍就是:随着模型参数量大小、数据集大小和用于训练的浮点数计算量的增加,模型的性能会提高。并且为了获得最佳性能,所有三个因素必须同时放大。当不受其他两…

每日OJ题_牛客OR57 手套

目录 牛客OR57 手套 解析代码 牛客OR57 手套 手套_牛客题霸_牛客网 class Gloves { public:int findMinimum(int n, vector<int> left, vector<int> right) {} }; 解析代码 class Gloves { public:int findMinimum(int n, vector<int> left, vector<i…

C++析构函数详解

目录 如果对你有帮助的话&#xff0c;点个赞吧&#xff01; 析构函数概念&#xff1a; 析构函数定义&#xff1a;类名前面加上~ 注意事项&#xff1a; 关于对象的销毁顺序&#xff1a; 析构函数概念&#xff1a; 在对象销毁的时候会自动调用析构函数&#xff0c;对相关资源…

Tomcat容器经常重启问题排查

报错代码: INFO [Catalina-utility-2] org.apache.catalina.core.StandardContext.reload Reloading Context with name [] has started1.查看内存占用情况:top 可以发现java线程正常情况下占用高达24%的内存资源 2.继续排查:top -Hp 29580 可以发现主要有子线程Catalina-ut…

探索ChatGPT在软件架构师工作中的应用

随着人工智能技术的不断发展&#xff0c;自然语言处理模型如OpenAI的ChatGPT已经成为了解决各种实际问题的强大工具之一。在软件架构师这个领域&#xff0c;ChatGPT也有着广泛的应用。本文将探讨软件架构师如何有效地利用ChatGPT来解决问题和提高工作效率。 ChatGPT简介 Chat…

Java高级编程—注解

文章目录 1.注解的概述2.常见的Annotation示例2.1 生成文档相关的注解2.2 在编译时进行格式检查的注解2.3 跟踪代码依赖性&#xff0c;实现替代配置文件功能的注解 3.自定义Annotation4.JDK中的元注解4.1 Retention4.2 Target4.3 Documented & Inherited 5. JDK8中注解的新…

vue 中的性能优化

1&#xff09;编码优化 尽量减少data中的数据&#xff0c;data中的数据都会增加getter和setter&#xff0c;会收集对应的watcherv-if和v-for不能连用如果需要使用v-for给每项元素绑定事件时使用事件代理SPA 页面采用keep-alive缓存组件在更多的情况下&#xff0c;使用v-if替代…

服务器出现故障如何恢复数据?

服务器数据恢复案例之服务器raid6中3块硬盘离线导致阵列崩溃的数据恢复案例 服务器故障&#xff1a; 服务器中有一组由6块盘组建的 RAID6&#xff0c;这台网站服务器上运行MYSQL数据库和存放其它类型的文件。该组raid中有两块磁盘离线&#xff0c;管理员没有及时更换磁盘&#…