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

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版…...

【Postman接口测试】Postman的安装和使用

在软件测试领域&#xff0c;接口测试是保障软件质量的关键环节之一&#xff0c;而Postman作为一款功能强大且广受欢迎的接口测试工具&#xff0c;能够帮助测试人员高效地进行接口测试工作。本文将详细介绍Postman的安装和使用方法&#xff0c;让你快速上手这款工具。 一、Pos…...

miniconda学习笔记

文章主要内容&#xff1a;演示miniconda切换不同python环境&#xff0c;安装python库&#xff0c;使用pycharm配置不同的conda建的python环境 目录 一、miniconda 1. 是什么&#xff1f; 2.安装miniconda 3.基本操作 一、miniconda 1. 是什么&#xff1f; miniconda是一个anac…...

区块链项目孵化与包装设计:从概念到市场的全流程指南

区块链技术的快速发展催生了大量创新项目&#xff0c;但如何将一个区块链项目从概念孵化成市场认可的产品&#xff0c;是许多团队面临的挑战。本文将从孵化策略、包装设计和市场落地三个维度&#xff0c;为你解析区块链项目成功的关键步骤。 一、区块链项目孵化的核心要素 明确…...

JavaScript的基本组成

1、JavaScript的组成部分 JavaScript可以分为三个部分&#xff1a;ECMAScript标准、DOM、BOM。 ECMAScript标准 即JS的基本语法&#xff0c;JavaScript的核心&#xff0c;描述了语言的基本语法和数据类型&#xff0c;ECMAScript是一套标 准&#xff0c;定义了一种语言…...

[Linux]从零开始的STM32MP157 U-Boot移植

一、前言 在上一次教程中&#xff0c;我们了解了STM32MP157的启动流程与安全启动机制。我们还将FSBL的相关代码移植成功了。大家还记得FSBL的下一个步骤是什么吗&#xff1f;没错&#xff0c;就是SSBL&#xff0c;而且常见的我们将SSBL作为存放U-Boot的地方。所以本次教程&…...

【Unity3D】实现横版2D游戏——攀爬绳索(简易版)

目录 GeneRope.cs 场景绳索生成类 HeroColliderController.cs 控制角色与单向平台是否忽略碰撞 HeroClampController.cs 控制角色攀爬 OnTriggerEnter2D方法 OnTriggerStay2D方法 OnTriggerExit2D方法 Update方法 开始攀爬 结束攀爬 Sensor_HeroKnight.cs 角色触发器…...

【llm对话系统】大模型 Llama 源码分析之 LoRA 微调

1. 引言 微调 (Fine-tuning) 是将预训练大模型 (LLM) 应用于下游任务的常用方法。然而&#xff0c;直接微调大模型的所有参数通常需要大量的计算资源和内存。LoRA (Low-Rank Adaptation) 是一种高效的微调方法&#xff0c;它通过引入少量可训练参数&#xff0c;固定预训练模型…...

算法随笔_35: 每日温度

上一篇:算法随笔_34: 最后一个单词的长度-CSDN博客 题目描述如下: 给定一个整数数组 temperatures &#xff0c;表示每天的温度&#xff0c;返回一个数组 answer &#xff0c;其中 answer[i] 是指对于第 i 天&#xff0c;下一个更高温度出现在几天后。如果气温在这之后都不会升…...

嵌入式硬件篇---CPUGPUTPU

文章目录 第一部分&#xff1a;处理器CPU&#xff08;中央处理器&#xff09;1.通用性2.核心数3.缓存4.指令集5.功耗和发热 GPU&#xff08;图形处理器&#xff09;1.并行处理2.核心数量3.内存带宽4.专门的应用 TPU&#xff08;张量处理单元&#xff09;1.为深度学习定制2.低精…...

STM32 PWM驱动舵机

接线图&#xff1a; 这里将信号线连接到了开发板的PA1上 代码配置&#xff1a; 这里的PWM配置与呼吸灯一样&#xff0c;呼吸灯连接的是PA0引脚&#xff0c;输出比较单元用的是OC1通道&#xff0c;这里只需改为OC2通道即可。 完整代码&#xff1a; #include "servo.h&quo…...

设计心得——平衡和冗余

一、平衡 在前面分析了一些软件设计的基础和原则后&#xff0c;今天分析一下整体设计上的一些实践问题。首先分析一下设计上的平衡问题。平衡非常好理解&#xff0c;看到过天平或者标称的同学们应该都知道什么平衡。无论在哪个环境里&#xff0c;平衡都是稳定的基础。 既然说到…...

webrtc协议详细解释

### 一、概述与背景 WebRTC&#xff08;Web Real-Time Communication&#xff09;最早由 Google 在 2011 年开源&#xff0c;旨在为浏览器与移动端应用提供客户端直连&#xff08;点对点&#xff09;方式进行实时音视频及数据传输的能力。传统的网络应用在进行高实时性音视频通…...

动手学强化学习(四)——蒙特卡洛方法

一、蒙特卡洛方法 蒙特卡洛方法是一种无模型&#xff08;Model-Free&#xff09;的强化学习算法&#xff0c;它通过直接与环境交互采样轨迹&#xff08;episodes&#xff09;来估计状态或动作的价值函数&#xff08;Value Function&#xff09;&#xff0c;而不需要依赖环境动态…...

网络原理(3)—— 传输层详解

目录 一. 再谈端口号 二. UDP协议(用户数据报协议) 2.1 UDP协议端格式 2.2 UDP报文长度 2.3 UDP校验和 三. TCP协议(传输控制协议) 3.1 TCP协议段格式 3.2 核心机制 3.2.1 确认应答 —— “感知对方是否收到” 3.2.2 超时重传 3.3.3 连接管理 —— 三次握手与四…...

2025美赛美国大学生数学建模竞赛A题完整思路分析论文(43页)(含模型、可运行代码和运行结果)

2025美国大学生数学建模竞赛A题完整思路分析论文 目录 摘要 一、问题重述 二、 问题分析 三、模型假设 四、 模型建立与求解 4.1问题1 4.1.1问题1思路分析 4.1.2问题1模型建立 4.1.3问题1样例代码&#xff08;仅供参考&#xff09; 4.1.4问题1样例代码运行结果&…...

Elasticsearch的开发工具(Dev Tools)

目录 说明1. **Console**2. **Search Profiler**3. **Grok Debugger**4. **Painless Lab**总结 说明 Elasticsearch的开发工具&#xff08;Dev Tools&#xff09;在Kibana中提供了多种功能强大的工具&#xff0c;用于调试、优化和测试Elasticsearch查询和脚本。以下是关于Cons…...

Python-基于PyQt5,pdf2docx,pathlib的PDF转Word工具

前言:日常生活中,我们常常会跟WPS Office打交道。作表格,写报告,写PPT......可以说,我们的生活已经离不开WPS Office了。与此同时,我们在这个过程中也会遇到各种各样的技术阻碍,例如部分软件的PDF转Word需要收取额外费用等。那么,可不可以自己开发一个小工具来实现PDF转…...

小程序-视图与逻辑

前言 1. 声明式导航 open-type"switchTab"如果没有写这个&#xff0c;因为是tabBar所以写这个&#xff0c;就无法跳转。路径开始也必须为斜线 open-type"navigate"这个可以不写 现在开始实现后退的效果 现在我们就在list页面里面实现后退 2.编程式导航…...

UE5制作视差图

双目深度估计开源数据集很多都是用UE制作的&#xff0c;那么我们自己能否通过UE制作自己想要的场景的数据集呢。最近花了点时间研究了一下&#xff0c;分享给需要的小伙伴。 主要使用的是UnrealCV插件&#xff0c;UnrealCV是一个开源项目&#xff0c;旨在帮助计算机视觉研究人…...

React Native 开发环境搭建(全平台详解)

React Native 开发环境搭建&#xff08;全平台详解&#xff09; 在开始使用 React Native 开发移动应用之前&#xff0c;正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南&#xff0c;涵盖 macOS 和 Windows 平台的配置步骤&#xff0c;如何在 Android 和 iOS…...

QMC5883L的驱动

简介 本篇文章的代码已经上传到了github上面&#xff0c;开源代码 作为一个电子罗盘模块&#xff0c;我们可以通过I2C从中获取偏航角yaw&#xff0c;相对于六轴陀螺仪的yaw&#xff0c;qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

【网络安全产品大调研系列】2. 体验漏洞扫描

前言 2023 年漏洞扫描服务市场规模预计为 3.06&#xff08;十亿美元&#xff09;。漏洞扫描服务市场行业预计将从 2024 年的 3.48&#xff08;十亿美元&#xff09;增长到 2032 年的 9.54&#xff08;十亿美元&#xff09;。预测期内漏洞扫描服务市场 CAGR&#xff08;增长率&…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?

论文网址&#xff1a;pdf 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若有发现欢迎评论指正&#xff01;文章偏向于笔记&#xff0c;谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...

【项目实战】通过多模态+LangGraph实现PPT生成助手

PPT自动生成系统 基于LangGraph的PPT自动生成系统&#xff0c;可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析&#xff1a;自动解析Markdown文档结构PPT模板分析&#xff1a;分析PPT模板的布局和风格智能布局决策&#xff1a;匹配内容与合适的PPT布局自动…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包

文章目录 现象&#xff1a;mysql已经安装&#xff0c;但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时&#xff0c;可能是因为以下几个原因&#xff1a;1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

【Oracle】分区表

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合

在汽车智能化的汹涌浪潮中&#xff0c;车辆不再仅仅是传统的交通工具&#xff0c;而是逐步演变为高度智能的移动终端。这一转变的核心支撑&#xff0c;来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒&#xff08;T-Box&#xff09;方案&#xff1a;NXP S32K146 与…...

WPF八大法则:告别模态窗口卡顿

⚙️ 核心问题&#xff1a;阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程&#xff0c;导致后续逻辑无法执行&#xff1a; var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题&#xff1a…...

Qt的学习(一)

1.什么是Qt Qt特指用来进行桌面应用开发&#xff08;电脑上写的程序&#xff09;涉及到的一套技术Qt无法开发网页前端&#xff0c;也不能开发移动应用。 客户端开发的重要任务&#xff1a;编写和用户交互的界面。一般来说和用户交互的界面&#xff0c;有两种典型风格&…...