C++初阶 -- 手撕string类(模拟实现string类)
目录
一、string类的成员变量
二、构造函数
2.1 无参版本
2.2 有参版本
2.3 缺省值版本
三、析构函数
四、拷贝构造函数
五、c_str函数
六、operator=重载
七、size函数
八、迭代器iterator
8.1 正常版本
8.2 const版本
九、operator[]
9.1 正常版本
9.2 const版本
十、reserve函数
十一、push_back函数
十二、append函数 -- 字符串版本
十三、operator+=
13.1 尾插字符
13.2 尾插字符串
十四、insert函数
十五、erase函数
十六、find函数
十七、swap函数
十八、 substr函数
十九、clear函数
二十、operator<< 和 operator >>
一、string类的成员变量
private:char* _str;size_t _size;size_t _capacity;const static size_t npos = -1;
二、构造函数
2.1 无参版本
// 无参
string()
{_str = new char[1];_str[0] = '\0';_size = 0;_capacity = 0;
}
2.2 有参版本
//有参
string(const char* str)
{_size = strlen(str);_capacity = _size;_str = new char[_capacity + 1];strcpy(_str, str);
}
2.3 缺省值版本
事实上,string类的构造函数不可能有两个版本。所以可以使用缺省值来实现构造函数
// 缺省参数
string(const char* str = "")
{_size = strlen(str);_capacity = _size;_str = new char[_capacity + 1];strcpy(_str, str);
}
唯一需要注意的是缺省参数该怎么给?
- 由于strlen()是遍历字符串直到遇到'\0'才结束,所以缺省值不能给nullptr,因为strlen会对指针进行解引用。
- 也不能给'\0'。因为'\0'是字符常量,而str是字符指针,它两类型不匹配,所以也会报错。
三、析构函数
当_str指向的空间为空时,delete函数内部会有判断机制。如果是空指针,delete函数不会运行。
// 析构函数
~string()
{delete[] _str;_str = nullptr;_size = _capacity = 0;
}
四、拷贝构造函数
// 拷贝构造函数
string(const string& str)
{// 传统版本_str = new char[str._capacity + 1];strcpy(_str, str._str);_size = str._size;_capacity = str._capacity;
}
五、c_str函数
// c_str()函数
const char* c_str() const
{return _str;
}
六、operator=重载

// operator= 重载
string& operator=(const string& s)
{if (this != &s){char* tmp = new char[s._capacity + 1];strcpy(tmp, s._str);delete[] _str;_str = tmp;_size = s._size;_capacity = s._capacity;}return *this;
}
七、size函数
// size()函数
size_t size() const
{return _size;
}
八、迭代器iterator
8.1 正常版本
typedef char* iterator;// 非const版本的迭代器
iterator begin()
{return _str;
}iterator end()
{return _str + _size;
}
8.2 const版本
typedef const char* const_iterator;// const版本的迭代器
const_iterator begin() const
{return _str;
}const_iterator end() const
{return _str + _size;
}
九、operator[]
- operator[]运算符重载,由于string类对象并不是内置类型,所以想要获取字符串里的字符就得用[下标]的方式。
- operator[]不仅仅可以读也可以写,所以返回类型就不能是char,而是使用引用返回char&。
9.1 正常版本
// []运算符重载 -- 非const版本
char& operator[](size_t pos)
{assert(pos <= _size);return _str[pos];
}
9.2 const版本
// []运算符重载 -- const版本
const char& operator[](size_t pos) const
{assert(pos <= _size);return _str[pos];
}
十、reserve函数
由于_size和_capacity只包括有效字符而不包括'\0'。所以要默认多开一个空间来存放'\0'。
// reserve()函数 -- 新开一个大小为n+1的空间,然后把原数组的数据拷贝到新数组,再delete原数组,最后指针指向新数组
void reserve(size_t n)
{if (n > _capacity){// 开辟的空间+1代表给'\0'也开了个空间char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}
}
十一、push_back函数
- 对于追加单个字符来说,因为追加字符的数量是已知的,所以可以用reserve函数来控制字符串的容量。
- 在追加字符之前首先得先判定当前字符的数量是否等于字符串的容量。等于就扩容。不等于就正常插入即可。
// push_back()函数
void push_back(char ch)
{if (_size == _capacity){size_t NewCapacity = _capacity == 0 ? 4 : 2 * _capacity;reserve(NewCapacity);}_str[_size] = ch;++_size;_str[_size] = '\0';
}
十二、append函数 -- 字符串版本
字符串相较于字符比较难以控制追加的数量,所以得先求出追加字符串的长度,再判断追加字符串的长度 + 当前字符串的长度是否大于当前容器的容量。
大于就扩容,不大于就使用strcpy函数在已重新扩容的字符串中尾插待插入字符串。
// append()函数
void append(const char* s)
{size_t len = strlen(s);if (len + _size > _capacity){reserve(len + _size);}strcpy(_str + _size, s);_size += len;
}
十三、operator+=
13.1 尾插字符
尾插字符就复用push_back函数
// operator+=重载 -- 字符
string& operator+= (char ch)
{push_back(ch);return *this;
}
13.2 尾插字符串
尾插字符串就复用append函数
// operator+=重载 -- 字符串
string& operator+= (const char* str)
{append(str);return *this;
}
十四、insert函数
// insert()函数 -- 插入字符串
string& insert(size_t pos, const char* str)
{assert(pos < _size);size_t len = strlen(str);if (len + _size > _capacity){reserve(len + _size);}//size_t end = _size;int end = _size;while (end >= (int)pos) // 防止发生隐式类型转换{_str[end + len] = _str[end];--end;}strncpy(_str + pos, str, len);_size += len;return *this;
}

十五、erase函数
首先得先判断len是否等于缺省值npos或者 len + pos 是否大于等于字符串实际存储有效字符的数量。如果出现以上两种情况直接在字符串中下标为pos的值赋值为'\0',再把pos赋给_size。
// erase()函数
void erase(size_t pos = 0, size_t len = npos)
{if (len == npos || pos + len >= _size){_str[pos] = '\0';_size = pos;}else{strcpy(_str + pos, _str + pos + len);}
}
十六、find函数
用strstr函数找到要找字符串的地址,如果strstr函数返回值为空指针就返回npos。
反之则用返回的指针 - 当前字符串的指针。
// find()函数 -- 寻找字符
size_t find(char ch, size_t pos = 0) const
{for (size_t i = pos; i < _size; i++){if (ch == _str[i]){return i;}}return npos;
}// find()函数 -- 寻找字符串
size_t find(const char* s , size_t pos = 0) const
{const char* ptr = strstr(_str + pos, s);if (ptr == nullptr){return npos;}else{return ptr - _str;}
}
十七、swap函数
// swap()函数
void swap(string& str)
{std::swap(_str, str._str);std::swap(_size, str._size);std::swap(_capacity, str._capacity);
}

十八、 substr函数
// substr()函数
string& substr(size_t pos = 0, size_t len = npos)
{assert(pos <= _size);size_t end = pos + len;if (len == pos || pos + len >= _size){end = _size;}string str;// 开一个新空间给子字符串,容量为end - posstr.reserve(end - pos);// 尾插到新字符串中for (size_t i = pos; i < len; i++){str += _str[i];}return str;
}
十九、clear函数
// clear()函数
void clear()
{_size = 0;_str[0] = '\0';
}
二十、operator<< 和 operator >>
// 流插入重载 <<
ostream& operator<< (ostream& out, const string& s)
{for (char ch : s){out << ch;}return out;
}// 流提取重载 >>
istream& operator>> (istream& in, string& s)
{s.clear();// 提取缓冲区里的字符,遇到' '和'\n'就结束char ch = in.get();char buff[128];size_t i = 0;while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == 127){buff[i] = '\0';s += buff;i = 0;}ch = in.get();}buff[i] = '\0';s += buff;return in;
}
相关文章:
C++初阶 -- 手撕string类(模拟实现string类)
目录 一、string类的成员变量 二、构造函数 2.1 无参版本 2.2 有参版本 2.3 缺省值版本 三、析构函数 四、拷贝构造函数 五、c_str函数 六、operator重载 七、size函数 八、迭代器iterator 8.1 正常版本 8.2 const版本 九、operator[] 9.1 正常版本 9.2 const版…...
【Unity3D】实现2D角色/怪物死亡消散粒子效果
核心:这是一个Unity粒子系统自带的一种功能,可将粒子生成控制在一个Texture图片网格范围内,并且粒子颜色会自动采样图片的像素点颜色,之后则是粒子编辑出消散效果。 Particle System1物体(爆发式随机速度扩散10000个粒…...
构建一个数据分析Agent:提升分析效率的实践
在上一篇文章中,我们讨论了如何构建一个智能客服Agent。今天,我想分享另一个实际项目:如何构建一个数据分析Agent。这个项目源于我们一个金融客户的真实需求 - 提升数据分析效率,加快决策速度。 从分析师的痛点说起 记得和分析师团队交流时的场景: 小张ÿ…...
85.[1] 攻防世界 WEB easyphp
进入靶场 属于代码审计 <?php // 高亮显示当前 PHP 文件的源代码,常用于调试或展示代码 highlight_file(__FILE__);// 初始化两个标志变量,用于后续条件判断 $key1 0; $key2 0;// 从 GET 请求中获取参数 a 和 b $a $_GET[a]; $b $_GET[b];// 检…...
嵌入式硬件篇---CPUGPUTPU
文章目录 第一部分:处理器CPU(中央处理器)1.通用性2.核心数3.缓存4.指令集5.功耗和发热 GPU(图形处理器)1.并行处理2.核心数量3.内存带宽4.专门的应用 TPU(张量处理单元)1.为深度学习定制2.低精…...
pytorch图神经网络处理图结构数据
人工智能例子汇总:AI常见的算法和例子-CSDN博客 图神经网络(Graph Neural Networks,GNNs)是一类能够处理图结构数据的深度学习模型。图结构数据由节点(vertices)和边(edges)组成&a…...
海外问卷调查,最常用到的渠道查有什么特殊之处
市场调研,包含市场调查和市场研究两个步骤,是企业和机构根据经营方向而做出的决策问题,最终通过海外问卷调查中的渠道查,来系统地设计、收集、记录、整理、分析、研究市场反馈的工作流程。 市场调研的工作流程包括:确…...
【Uniapp-Vue3】解决uni-popup弹窗在安全区显示透明问题
我们在使用uni-popup时,如果想要给弹出内容添加一个背景颜色,我们会发现在安全区域是不显示该背景颜色的。 首先根据如下的目录结构找到uni-popup.vue文件 在该文件中找到bottom配置,将红箭头所指代码注释掉 下面的安全区域就没有了ÿ…...
什么是麦克斯韦方程
飞书链接,格式更好,⭐⭐⭐:长尾 - 什么是麦克斯韦方程 基于作者的内容,做了一些扩展(问了 DeepSeek) 最美的公式:你也能懂的麦克斯韦方程组(积分篇) 04通量的引入 用一个…...
webrtc peerconnection_client peerconnection_server 连接失败问题解决 win10 win11
0 常见问题 (1) webrtc peerconnection_client 连接 peerconnection_server 无连接列表 (2)连接导致崩溃debug状态下因为这个断言 RTC_DCHECK_RUN_ON(&capture_checker_); 1 在 peerconnection\client\main.cc 当中 定义类 class CustomSock…...
项目练习:重写若依后端报错cannot be cast to com.xxx.model.LoginUser
文章目录 一、情景说明二、解决办法 一、情景说明 在重写若依后端服务的过程中 使用了Redis存放LoginUser对象数据 那么,有存就有取 在取值的时候,报错 二、解决办法 方法1、在TokenService中修改如下 getLoginUser 方法中:LoginUser u…...
2025年2月1日(Keep calm and code Python)
“Keep calm and code Python” 的意思是 “保持冷静,编写 Python 代码”。 这句话来源于 “Keep Calm and Carry On”(保持冷静,继续前进),这是二战时期英国政府的宣传口号。后来,这种句式被广泛模仿&…...
核心集:DeepCore: A Comprehensive Library for CoresetSelection in Deep Learning
目录 一、TL;DR 二、为什么研究核心集? 三、问题定义和如何做 3.1 问题定义 3.2 业界方法 3.2.1 基于几何的方法 3.2.2 基于不确定性的方法 3.2.3 基于误差/损失的方法 3.2.5 GraNd 和 EL2N 分数 3.2.6 重要性采样 3.2.7 基于决策边界的办法 …...
Hot100之矩阵
73矩阵置零 题目 思路解析 收集0位置所在的行和列 然后该行全部初始化为0 该列全部初始化为0 代码 class Solution {public void setZeroes(int[][] matrix) {int m matrix.length;int n matrix[0].length;List<Integer> list1 new ArrayList<>();List<…...
可视化相机pose colmap形式的相机内参外参
目录 内参外参转换 可视化相机pose colmap形式的相机内参外参 内参外参转换 def visualize_cameras(cameras, images):fig plt.figure()ax fig.add_subplot(111, projection3d)for image_id, image_data in images.items():qvec image_data[qvec]tvec image_data[tvec]#…...
第十二章 I 开头的术语
文章目录 第十二章 I 开头的术语以 I 开头的术语被识别 (identified by)识别关系 (identifying relationship)身份 (identity)idkey隐式全局引用 (implicit global reference)隐含命名空间 (implied namespace)包含文件 (include file)传入锁 (incoming lock) 索引 (index)索引…...
C# 类与对象详解
.NET学习资料 .NET学习资料 .NET学习资料 在 C# 编程中,类与对象是面向对象编程的核心概念。它们让开发者能够将数据和操作数据的方法封装在一起,从而构建出模块化、可维护且易于扩展的程序。下面将详细介绍 C# 中类与对象的相关知识。 一、类的定义 …...
Windsurf cursor vscode+cline 与Python快速开发指南
Windsurf简介 Windsurf是由Codeium推出的全球首个基于AI Flow范式的智能IDE,它通过强大的AI助手功能,显著提升开发效率。Windsurf集成了先进的代码补全、智能重构、代码生成等功能,特别适合Python开发者使用。 Python环境配置 1. Conda安装…...
深度解析:网站快速收录与服务器性能的关系
本文转自:百万收录网 原文链接:https://www.baiwanshoulu.com/37.html 网站快速收录与服务器性能之间存在着密切的关系。服务器作为网站运行的基础设施,其性能直接影响到搜索引擎对网站的抓取效率和收录速度。以下是对这一关系的深度解析&am…...
Linux tr 命令使用详解
简介 tr (translate)命令用于在 Linux 中翻译或删除输入流(通常是 stdin )中的字符。它主要用于文本操作,并且可以作为转换或删除文本文件或流中的特定字符的方便工具。 基本语法 tr [OPTION] [SET1] [SET2]SET1&am…...
数据库内存与Buffer Pool
数据库内存与Buffer Pool 文章目录 数据库内存与Buffer Pool一:MySQL内存结构1:MySQL工作组件2:工作线程的本地内存3:共享内存区域4:存储引擎缓冲区 二:InnoDB的核心:Buffer Pool1:数…...
程序员学英文之At the Airport Customs
Dialogue-1 Making Airline Reservation预定机票 My cousin works for Xiamen Airlines. 我表哥在厦航上班。I’d like to book an air ticket. 我想预定一张机票。Don’t judge a book by its cover. 不要以貌取人。I’d like to book / re-serve a table for 10. 我想预定一…...
Redis代金卷(优惠卷)秒杀案例-单应用版
优惠卷表:优惠卷基本信息,优惠金额,使用规则 包含普通优惠卷和特价优惠卷(秒杀卷) 优惠卷的库存表:优惠卷的库存,开始抢购时间,结束抢购时间.只有特价优惠卷(秒杀卷)才需要填写这些信息 优惠卷订单表 卷的表里已经有一条普通优惠卷记录 下面首先新增一条秒杀优惠卷记录 { &quo…...
51单片机 01 LED
一、点亮一个LED 在STC-ISP中单片机型号选择 STC89C52RC/LE52RC;如果没有找到hex文件(在objects文件夹下),在keil中options for target-output- 勾选 create hex file。 如果要修改编程 :重新编译-下载/编程-单片机重…...
MusicFree-开源的第三方音乐在线播放和下载工具, 支持歌单导入[对标落雪音乐]
MusicFree 链接:https://pan.xunlei.com/s/VOI0RrVLTTWE9kkpt0U7ofGBA1?pwd4ei6#...
消息队列篇--原理篇--常见消息队列总结(RabbitMQ,Kafka,ActiveMQ,RocketMQ,Pulsar)
1、RabbitMQ 特点: AMQP协议:RabbitMQ是基于AMQP(高级消息队列协议)构建的,支持多种消息传递模式,如发布/订阅、路由、RPC等。多语言支持:支持多种编程语言的客户端库,包括Java、P…...
nacos 配置管理、 配置热更新、 动态路由
文章目录 配置管理引入jar包添加 bootstrap.yaml 文件配置在application.yaml 中添加自定义信息nacos 配置信息 配置热更新采用第一种配置根据服务名确定配置文件根据后缀确定配置文件 动态路由DynamicRouteLoaderNacosConfigManagerRouteDefinitionWriter 路由配置 配置管理 …...
程序代码篇---Numpyassert迭代器
文章目录 前言第一部分:Numpy1. 创建数组2. 数组索引和切片3. 数组形状操作4. 数组运算5. 数学函数6. 随机数生成7. 数组排序 第二部分:assert基本语法1.condition2.error_message 示例注意事项断言的用途 第三部分:迭代器迭代器协议1.__iter…...
(笔记+作业)书生大模型实战营春节卷王班---L0G2000 Python 基础知识
学员闯关手册:https://aicarrier.feishu.cn/wiki/QtJnweAW1iFl8LkoMKGcsUS9nld 课程视频:https://www.bilibili.com/video/BV13U1VYmEUr/ 课程文档:https://github.com/InternLM/Tutorial/tree/camp4/docs/L0/Python 关卡作业:htt…...
分布式微服务系统架构第90集:现代化金融核心系统
#1.1 深化数字化转型,核心面临新挑战 1、架构侧:无法敏捷协同数字金融经营模式转型。 2、需求侧:业务需求传导低效始终困扰金融机构。 3、开发侧:创新产品上市速度低于期望。 4、运维侧:传统面向资源型监控体系难以支撑…...
