【C++】string的底层剖析以及模拟实现
一、字符串类的认识
C语言中,字符串是以'\0'结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数, 但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。在OJ中,有关字符串的题目基本以string类的形式出现,而且在常规工作中,为了简单、方便、快捷,基本 都使用string类,很少有人去使用C库中的字符串操作函数。为了增加自己对于string的理解,自己将模仿库中string类有的方法,设计一个简单的string类。其中类成员包括以下:
class string{private:char* _str;//字符串首地址size_t _capacity;//字符串容量size_t _size;//有效数据的个数public:typedef char* iterator;}
二、库中string常用的方法
我主要会实现string中经常会用到的方法,若大家想要了解更多关于string的细节,可以登录这个C++查询网站https://cplusplus.com/reference/自行查询。下面是一些常用方法以及代码片段,可能前面出现的方法会用到后面出现的方法的实现,若有疑问可以看最后面的完整代码
正向迭代器
iterator begin()
{return _str;
}iterator end()
{return _str + _size;
}
+=
string& operator+=(char c){if (_size == _capacity){_capacity = _capacity == 0 ? 4 : 2 * _capacity;char* tmp = new char[_capacity +1];strcpy(tmp, _str);delete[] _str;_str = tmp;}_str[_size] = c;_str[_size + 1] = '\0';_size++;return *this;}string& operator+=(const char* str){append(str);return *this;}
push_back(尾插)
void push_back(char c){*this += c;}
append(在字符串末尾追加)
void append(const char* str){int i = 0;while (str[i]){push_back(str[i]);i++;}}
clear(清除掉字符串的数据)
void clear(){_size = 0;_str[0] = '\0';}
swap(交换两个字符串的内容)
void swap(string& s){std::swap(_str,s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}
c_str(返回字符串的首地址)
const char* c_str()const{return _str;}
resize(将字符串设定为指定大小,字符串占满所开辟的空间)
void resize(size_t n, char c = '\0'){if (n > _capacity){reserve(n);for (int i = _size; i < _capacity; i++){_str[i] = c;}_size = _capacity;}else{_size = n;}}
reserve(预开辟出空间,字符串还是原来的大小(一般不缩容))
void reserve(size_t n){if (n > _capacity){_capacity = n;char* tmp = new char[_capacity + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;}}
find(返回字符c在string中第一次出现的位置/返回子串s在string中第一次出现的位置)
size_t find(char c, size_t pos = 0) const{for (size_t i = pos; i < _size; i++){if (_str[i] == c)return i;}return std::string::npos;}size_t find(const char* s, size_t pos = 0) const{const char* ptr = std::strstr(_str + pos, s);if (ptr == nullptr)return std::string::npos;else{return ptr - _str;}}
insert(在pos位置上插入字符c/字符串str,并返回该字符的位置)
string& insert(size_t pos, char c){if (_size == _capacity){reserve(_capacity == 0 ? 4 : 2 * _capacity);}size_t end = _size - 1;while (end >= pos){_str[end + 1] = _str[end];end--;}_str[pos] = c;return *this;}string& insert(size_t pos, const char* str){int len = 0;while (str[len++]);if (_size + len > _capacity){reserve(_size + len);}memmove(_str + pos + len, _str + pos, len * sizeof(char));for (int i = pos; i < pos + len; i++){_str[i] = str[i - pos];}_size += len;return *this;}
erase(删除pos位置上的元素,并返回该string)
string& erase(size_t pos, size_t len){memmove(_str + pos, _str + pos + len, (_size - pos-len) * sizeof(char));_size -= len;return *this;}
三、完整代码
//string.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string>
//using namespace std;namespace sxb
{class string{friend std::ostream& operator<<(std::ostream& _cout, const string& s);friend std::istream& operator>>(std::istream& _cin, string& s);private:char* _str;size_t _capacity;size_t _size;public:typedef char* iterator;public:string(const char* str = ""){//_str = str;int len = 0;while(str[len] != ' ' && str[len] != '\0'){len++;}_str = new char[len + 1];for (int i = 0; i < len; i++){_str[i] = str[i];}_str[len] = '\0';_capacity = len;_size = len;}string(const string& s){_str = new char[s.size() + 1];strcpy(_str, s.c_str());_str[s.size()] = '\0';_capacity = s.size();_size = s.size();}string& operator=(const string& s){for (int i = 0; i < size(); i++){_str += s[i];}return *this;}~string(){delete[] _str;_size = 0;_capacity = 0;}//// iteratoriterator begin(){return _str;}iterator end(){return _str + _size;}// /// // modifyvoid push_back(char c){*this += c;}string& operator+=(char c){if (_size == _capacity){_capacity = _capacity == 0 ? 4 : 2 * _capacity;char* tmp = new char[_capacity +1];strcpy(tmp, _str);delete[] _str;_str = tmp;}_str[_size] = c;_str[_size + 1] = '\0';_size++;return *this;}void append(const char* str){int i = 0;while (str[i]){push_back(str[i]);i++;}}string& operator+=(const char* str){append(str);return *this;}void clear(){_size = 0;_str[0] = '\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 _str[0] == '\0';}void resize(size_t n, char c = '\0'){if (n > _capacity){reserve(n);for (int i = _size; i < _capacity; i++){_str[i] = c;}_size = _capacity;}else{_size = n;}}void reserve(size_t n){if (n > _capacity){_capacity = n;char* tmp = new char[_capacity + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;}}///accesschar& operator[](size_t index){return _str[index];}const char& operator[](size_t index)const{return _str[index];}///relational operatorsbool operator==(const string& s){if (_size != s.size())return false;for (int i = 0; i < _size; i++){if (_str[i] != s[i])return false;}return true;}bool operator!=(const string& s){return !operator==(s);}返回c在string中第一次出现的位置size_t find(char c, size_t pos = 0) const{for (size_t i = pos; i < _size; i++){if (_str[i] == c)return i;}return std::string::npos;}返回子串s在string中第一次出现的位置size_t find(const char* s, size_t pos = 0) const{const char* ptr = std::strstr(_str + pos, s);if (ptr == nullptr)return std::string::npos;else{return ptr - _str;}}在pos位置上插入字符c/字符串str,并返回该字符的位置string& insert(size_t pos, char c){if (_size == _capacity){reserve(_capacity == 0 ? 4 : 2 * _capacity);}size_t end = _size - 1;while (end >= pos){_str[end + 1] = _str[end];end--;}_str[pos] = c;return *this;}string& insert(size_t pos, const char* str){int len = 0;while (str[len++]);if (_size + len > _capacity){reserve(_size + len);}memmove(_str + pos + len, _str + pos, len * sizeof(char));for (int i = pos; i < pos + len; i++){_str[i] = str[i - pos];}_size += len;return *this;}删除pos位置上的元素,并返回该元素的下一个位置string& erase(size_t pos, size_t len){memmove(_str + pos, _str + pos + len, (_size - pos-len) * sizeof(char));_size -= len;return *this;}};std::ostream& operator<<(std::ostream& _cout, const string& s){for (int i = 0; i < s.size(); i++){_cout << s[i];}return _cout;}std::istream& operator>>(std::istream& _cin, string& s){char buffer[128];int len = 0;char bu = _cin.get();while (bu != ' ' && bu != '\n'){buffer[len] = bu;len++;bu = _cin.get();}for (int i = 0; i < len; i++){s += buffer[i];}return _cin;}}
相关文章:

【C++】string的底层剖析以及模拟实现
一、字符串类的认识 C语言中,字符串是以\0结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数, 但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理&a…...

Unity的PICO项目基础环境搭建笔记(调试与构建应用篇)
文章目录 前言一、为设备开启开发者模式1、开启PICO VR一体机。前往设置>通用>关于本机>软件版本号2、一直点击 软件版本号 ,直到出现 开发者 选项3、进入 开发者模式,打开 USB调试,选择 文件传输 二、实时预览应用场景1、下载PC端的…...

电脑远程桌面选项变成灰色没办法勾选怎么办?
有些人在使用Windows系统自带的远程桌面工具时,会发现系统属性远程桌面选项卡中勾选启用“允许远程连接到此计算机”。 导致此问题出现的原因主要是由于组策略或者注册表设置错误造成的。 修复远程桌面选项变灰的两种方法! 方法一:设置本地组…...

2024.3.14
1.成员函数版本实现算术运算符的重载,全局函数版本实现算术运算符的重载 #include <iostream>using namespace std;class Room {friend const Room operator-(const Room &a,const Room &b); private:string a;int b; public:Room(){}Room(string a,int b):a(a)…...

chatGPT的耳朵!OpenAI的开源语音识别AI:Whisper !
语音识别是通用人工智能的重要一环!可以说是AI的耳朵! 它可以让机器理解人类的语音,并将其转换为文本或其他形式的输出。 语音识别的应用场景非常广泛,比如智能助理、语音搜索、语音翻译、语音输入等等。 然而,语音…...

C语言冒泡排序
冒泡排序是一种简单的排序算法,通过重复遍历要排序的数列,依次比较两个相邻的元素,如果它们的顺序错误则交换它们。这个过程会重复进行,直到没有相邻的元素需要交换,也就是数列已经排序完成。 冒泡排序的名字来源于其工…...

vue2 elementui 封装一个动态表单复杂组件
封装一个动态表单组件在 Vue 2 和 Element UI 中需要考虑到表单字段的动态添加、删除以及验证等复杂功能。下面是一个简单的例子,展示如何创建一个可以动态添加和删除字段的表单组件。 首先,你需要安装并引入 Element UI: bash 复制 npm in…...

基于智慧灯杆的智慧城市解决方案(2)
功能规划 智慧照明功能 智慧路灯的基本功能仍然是道路照明, 因此对照明功能的智慧化提升是最基本的一项要求。 对道路照明管理进行智慧化提升, 实施智慧照明, 必然将成为智慧城市中道路照明发展的主要方向之一。 智慧照明是集计算机网络技术、 通信技术、 控制技术、 数据…...

「Paraverse平行云」亮相HKSTP OPENHOUSE活动
🚀11月7日,「Paraverse平行云」参展香港科学园HKSTP一年一度的Open House活动! ✨ 众多专家、同行与我们驻足深入交流,探索实时云渲染解决方案LarkXR在在数字人、数字孪生、建筑信息模型(BIM)、3D建模、建筑…...

CubeMX使用教程(5)——定时器PWM输出
本篇我们将利用CubeMX产生频率固定、占空比可调的两路PWM信号输出 例如PA6引脚输出100Hz的PWM;PA7引脚输出500Hz的PWM,双路同时输出 我们还是利用上一章定时器中断的工程进行学习,这样比较方便 首先打开CubeMX对PA6、PA7进行GPIO配置 注&a…...

superset连接Apache Spark SQL(hive)过程中的各种报错解决
superset连接数据库官方文档:Installing Database Drivers | Superset 我们用的是Apache Spark SQL,所以首先需要安装下pyhive #命令既下载了pyhive也下载了它所依赖的其他安装包 pip install pyhive#多个命令也可下载 pip install sasl pip install th…...

Pulsar IO实战
一、引言 今天跟着 官方文档 基于docker玩一把Pulsar IO吧 二、概要 在用户能够轻松的将消息队列跟其他系统(数据库、其他消息系统)一起使用时,消息队列的作用才是最强大的。而Pulsar IO connectors可以让你很轻松的创建、部署以及管理这些跟外部系统的连接&#…...

Linux/Ubuntu/Debian基本命令:文本操作
Linux系统真的超级好用,免费,有很多开源且功能强大的软件。尤其是Ubuntu,真的可以拯救十年前的老电脑。 下面是用于在命令行界面(Terminal)中进行文本操作的键盘快捷键, 这些快捷方式对于高效的文本编辑非常…...

Self-supervised Contextual Keyword and Keyphrase Retrieval with Self-Labelling
文章目录 题目摘要方法数据集实验 题目 通过自我标记进行自我监督的上下文关键字和关键词短语检索 论文地址:https://www.preprints.org/manuscript/201908.0073/v1 项目地址:https://github.com/naister/Keyword-OpenSource-Data 摘要 在本文中&#x…...

新 树莓派4B 温湿度监测 基于debian12的树莓派OS
前言 本文旨在完成通过外接温湿度传感器至树莓派使得树莓派不断记录并存储温湿度数据 这个领域有很多文章,但是部分文章已经缺乏了时效性,在最新系统不适用,本文目前适用 硬件 硬件连接 温湿度传感器常选用DHT11和DHT22,淘宝…...

人工智能入门之旅:从基础知识到实战应用(一)
一、引言 人工智能(Artificial Intelligence,AI)是指利用计算机科学和技术模拟、延伸和扩展人类智能的理论、方法、技术和应用系统的学科。它的目标是使计算机系统具有类似于人类的智能,能够感知环境、学习、推理、规划、解决问题和交流。 在当今社会中,人工智能具有极其…...

GNN/GCN自己学习
一、图的基本组成 V:点(特征) E:边 U:图(全局特征) 二、用途 整合特征(embedding),做重构 三、邻接矩阵 以图像为例,每个像素点周围都有邻居,…...

honle电源维修UV电源控制器维修EVG EPS60
好乐UV电源控制器维修;honle控制器维修;UV电源维修MUC-Steuermodul 2 LΛmpen D-82166 主要维修型号: EVG EPS 60/120、EVG EPS 100、EVG EPS200、EVG EPS 220、EVG EPS 340、EVG EPS40C-HMI、EVG EPS60 HONLE好乐uv电源维修故障包括&#…...

【学习心得】Python好库推荐——websocket-client
websocket-client 是一个在 Python 中广泛使用的库,用于创建 WebSocket 客户端并实现与 WebSocket 服务器的双向通信。更多的关于websocket协议介绍,可以看看我之前写的文章哦! 【学习心得】websocket协议简介并与http协议对比http://t.csdn…...

3.1_8 两级页表
文章目录 3.1_8 两级页表(一)单级页表存在的问题(二)如何解决单级页表的问题?(三)两级页表的原理、地址结构(四)如何实现地址变换(五)需要注意的几…...

【SysBench】sysbench-1.20 命令速查表
1、通用语法 The general command line syntax for sysbench is: sysbench [options]... [testname] [command] testname is an optional name of a built-in test (e.g. fileio, memory, cpu, etc.), or a name of one of the bundled Lua scripts (e.g. oltp_read_only), or…...

neo4j网页无法打开,启动一会儿后自动关闭,查看neo4j status显示Neo4j is not running.
目录 前情提要User limit of inotify watches reached无法访问此网站 前情提要 公司停电,服务器未能幸免,发现无法访问此网站,http://0.0.0.0:7474 在此之前都还好着 User limit of inotify watches reached (base) [rootlocalhost ~]# n…...

一键卸载和安装 nvidia、cuda、cudnn、tensorrt
1. 卸载 nvidia、cuda、cudnn、tensorrt sudo apt purge \"cuda*" \"libcudnn*" \"libnvinfer*" \"libnvonnxparsers*" \"libnvparsers*" \"tensorrt*" \"nvidia*&…...

LeetCode 389. 找不同
文章目录 一、题目二、C 题解 一、题目 给定两个字符串 s 和 t ,它们只包含小写字母。 字符串 t 由字符串 s 随机重排,然后在随机位置添加一个字母。 请找出在 t 中被添加的字母。 示例 1: 输入:s “abcd”, t “abcde” 输出&…...

科技云报道:两会热议的数据要素,如何拥抱新技术?
科技云报道原创。 今年全国两会上,“数字经济”再次成为的热点话题。 2024年政府工作报告提到:要健全数据基础制度,大力推动数据开发开放和流通使用;适度超前建设数字基础设施,加快形成全国一体化算力体系࿱…...

【linux】进程管理:进程控制块、进程号、fork创建进程、特殊进程及exec函数族解析
一、进程的概述 可执行程序运行起来后(没有结束之前),它就成为了一个进程。程序是存放在存储介质上的一个可执行文件,而进程是程序执行的过程。进程的状态是变化的,其包括进程的创建、调度和消亡。程序是静态的,进程是…...

【DL经典回顾】激活函数大汇总(八)(Maxout Softmin附代码和详细公式)
激活函数大汇总(八)(Maxout & Softmin附代码和详细公式) 更多激活函数见激活函数大汇总列表 一、引言 欢迎来到我们深入探索神经网络核心组成部分——激活函数的系列博客。在人工智能的世界里,激活函数扮演着不…...

Docker进阶:深入了解 Dockerfile
Docker进阶:深入了解 Dockerfile 一、Dockerfile 概述二、Dockerfile 优点三、Dockerfile 编写规则四、Dockerfile 中常用的指令1、FROM2、LABEL3、RUN4、CMD5、ENTRYPOINT6、COPY7、ADD8、WORKDIR9、 ENV10、EXPOSE11、VOLUME12、USER13、注释14、ONBUILD 命令15、…...

【LeetCode热题100】206. 反转链表(链表)
一.题目要求 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。 二.题目难度 简单 三.输入样例 示例 1: 输入:head [1,2,3,4,5] 输出:[5,4,3,2,1] 示例 2: 输入:head [1,2…...

电玩城游戏大厅计时软件怎么用,佳易王计时计费管理系统软件定时语音提醒操作教程
电玩城游戏大厅计时软件怎么用,佳易王计时计费管理系统软件定时语音提醒操作教程 一、前言 以下软件操作教程以 佳易王电玩计时计费软件V18.0为例 说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 1、软件计时计费,只需点击开…...