【C++】手撕string类(超实用!)

前言

一、标准库中的string类

1.1 string类介绍

1.2 string的常用接口

1.2.1 常用的构造函数

1.2.2 容量操作接口

(1)size

(2)capacity 

(3)empty 

(4)clear 

(5)reserve 

(6)resize 

1.2.3 访问和遍历

(1)operator[] 

(2)迭代器 

(3)at 

(4)back

(5)front

(6)find

(7)rfind和npos

(8)c_str

1.2.4 修改字符串操作

(1)operator+=

(2)push_back

(3)append

(4)insert

(5)erase

(6)swap

(7)operator+

(8)getline

1.2.5 各种运算符重载函数

(1)operator>>和operator<<

(2)比较运算符

二、模拟实现string类


前言

学习string类之前,我们需要对STL库有一个简单的了解

STL(standard template library——标准模板库),是C++标准库的重要组成部分,不仅是一个可复用的组件库,还是一个包罗数据结构与算法的软件框架。

STL有六大组件:


一、标准库中的string类

1.1 string类介绍

string类是表示字符串的一个类,内部通常有三个成员变量:指向字符串的指针、字符串的有效元素个数和字符串的容量大小

char* _str;
size_t _size;
size_t _capacity;

我们通过string类中的成员函数(接口),就能对字符串进行各种操作

在使用string类时,必须包含头文件<string>和using namespace std;

1.2 string的常用接口

1.2.1 常用的构造函数

string();

默认构造函数,用于构造空的string类对象

例如:

void Test()
{string s1;
}
string(const char* s);

用一个常量字符串来构造string类对象

例如:

void Test()
{string s1("hello");
}
string(const string& s);

string类的拷贝构造函数

例如:

void Test()
{string s1("hello");string s2(s1);
}

1.2.2 容量操作接口

(1)size

size_t size() const;

返回字符串有效字符长度

string类中还有一个函数length和size的效果一样,最初只有length存在,为了和其他容器相同后面新增了size

例如:

(2)capacity 

size_t capacity() const;

返回字符串容量

例如:

(3)empty 

bool empty()  const;

 检测字符串是否为空串,为空返回true,否则返回false

例如:

(4)clear 

void clear();

用于清空有效字符,不改变字符串容量大小

例如:

(5)reserve 

void reserve(size_t n = 0);

为字符串预留空间

例如:

如果n比原容量小则不作改变

在vs上常常会开比n更大一些的空间

(6)resize 

void resize(size_t n);

void resize(size_t n, char c);

将有效字符的个数修改为n,并且如果n大于原来的_size,多出来的地方用字符c填充,不改变字符串容量大小

如果没有给出字符c,则用\0填充

例如:

1.2.3 访问和遍历

(1)operator[] 

char& operator[](size_t pos);

const char& operator[](size_t pos) const;

返回字符串中pos位置的字符

例如:

(2)迭代器 

iterator begin();

const_iterator begin() const;

iterator end();

const_iterator end() const;

迭代器,用于获取字符串第一个字符的位置和最后一个字符的下一个位置

例如:

reverse_iterator rbegin();

const_reverse_iterator rbegin() const;

reverse_iterator rend();

const_reverse_iterator rend() const;

反向迭代器,rbegin获取字符串最后一个字符的下一个位置,rend获取字符串的第一个位置

例如:

需要注意,这里rit是加加而不是减减

范围for的底层实际上也是迭代器

(3)at 

char& at(size_t pos);

const char& at(size_t pos) const;

返回字符串中pos位置的字符的引用

例如:

(4)back

char& back();

const char& back() const;

返回字符串最后一个字符的引用

例如:

(5)front

char& front();

const char& front() const;

返回字符第一个字符串的引用

例如:

(6)find

size_t find(char c, size_t pos = 0) const;

从字符串的pos位置向后找字符c,返回该字符在字符串中的位置

例如:

(7)rfind和npos

size_t rfind(char c, size_t pos = npos) const;

static const size_t nops = -1

从字符串的pos位置向前找字符c,返回该字符在字符串中的位置

npos是string类中定义的一个静态成员变量,类型为无符号整型,值为-1,因为是无符号转换后变成整型的最大值,也就是4294967295(42亿多),当我们不给pos的值时按照缺省值执行,默认从字符串尾部开始找起

例如:

(8)c_str

const char* c_str() const;

按照C语言的格式返回字符串

例如:

在hello后面加上\0和字符串world,重载后的流插入操作符函数会按照size的大小来打印字符串

而打印c_str的返回值,会遇到\0就停下

1.2.4 修改字符串操作

(1)operator+=

string& operator+=(const string& str);

string& operator+=(const char* s);

string& operator+=(char c);

在字符串后追加一个字符串或字符

例如:

(2)push_back

void push_back(char c);

在字符串后尾插一个字符c

例如:

(3)append

string& append(const string& str);

string& append(const char* s);

string& append(const char* s, size_t n);

string& append(size_t n, char c);

用于在字符串后加一个字符串、一个字符串的前n个字符或n个字符c

例如:

(4)insert

string& insert(size_t pos, const string& str);

string& insert(size_t pos, const char* s);

string& insert(size_t pos, const char* s, size_t n);

string& insert(size_t pos, size_t n, char c);

iterator insert(iterator p, char c);

用于在字符串的pos位置插入一个字符串、字符串的前n个字符或n个字符c

还有迭代器版本的insert,用法是在p的位置插入字符c 

例如:

(5)erase

string& erase(size_t pos, size_t len = npos);

iterator erase(iterator p);

iterator erase(iterator first, iterator last);

用于在字符串的pos位置删除len个字符

迭代器版本的erase,在p的位置删除一个字符,或者删除 [ first , last ) 内的字符

例如:

(6)swap

void swap(string& str);

用于交换两个string类对象

string类中的swap函数相比标准库中的swap函数,交换string类对象的效率更高

例如:

(7)operator+

string operator+(const string& lhs, const string& rhs);

string operator+(const string& lhs, const char* rhs);

string operator+(const char* lhs, const string& rhs);

string operator+(const string& lhs, char rhs);

string operator+(char lhs, const string& rhs);

返回一个新构造的string类对象,其值是lhs和rhs的合并

例如:

(8)getline

istream& getline(istream& is, string& str, char delim);

istream& getline(istream& is, string& str);

用于字符串的输入

相比cin遇到空格就停止提取,我们可以给出分隔符delim,遇到delim才停止提取,如果没有给出,则遇到换行停止提取

例如:

 

1.2.5 各种运算符重载函数

(1)operator>>和operator<<

istream& operator>>(istream& is, string& str);

ostream& operator<<(ostream& os, const string& str);

用于string对象的流提取和流插入

例如:

(2)比较运算符

各种比较运算符的重载函数,这里就不赘述了

用于比较两个字符串的对应位置的ASCII码值大小

例如:


二、模拟实现string类

知道了string类中各种常用接口的用法后,我们就可以开始自己手撕一个自己的string类了

为了不和标准库中的string类冲突,我们可以开一个自己的命名空间

完整代码如下:

namespace Eristic
{class string{friend ostream& operator<<(ostream& cout, const string& s);friend istream& operator>>(istream& cout, const 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(const char* str = ""):_size(strlen(str)){_capacity = _size == 0 ? 3 : _size;_str = new char[_capacity + 1];strcpy(_str, str);}void 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{size_t len = strlen(_str);return !len;}char& at(size_t pos){assert(pos < _size);return _str[pos];}const char& at(size_t pos) const{assert(pos < _size);return _str[pos];}char& back(){return at(_size - 1);}const char& back() const{return at(_size - 1);}char& front(){return at(0);}const char& front() const{return at(0);}void resize(size_t n, char ch = '\0'){if (n < _size){_size = n;_str[_size] = '\0';}else if (n > _size){if (n > _capacity){reserve(n);}for (size_t i = _size; i < n; i++){_str[i] = ch;}_size = n;_str[_size] = '\0';}}void push_back(char ch){if (_size + 2 > _capacity){reserve(_capacity * 2);}_str[_size] = ch;_size++;_str[_size] = '\0';//insert(_size, ch); //或者直接复用}void push_back(const char* str){append(str);}void append(const char* str){int len = strlen(str);if (_size + len > _capacity){reserve(_size + len);}strcpy(_str + _size, str);_size += len;}string& insert(size_t pos, char ch){assert(pos <= _size);if (_size + 1 > _capacity){reserve(_capacity * 2);}size_t end = _size + 1;while (end > pos){_str[end] = _str[end - 1];--end;}_str[pos] = ch;_size++;return *this;}string& insert(size_t pos, const char* str){assert(pos <= _size);size_t len = strlen(str);if (_size + len > _capacity){reserve(_size + len);}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;}string& erase(size_t pos, size_t len = npos){assert(pos < _size);if (len >= _size - pos){_str[pos] = '\0';}else{strcpy(_str + pos, _str + pos + len);}_size -= len;return *this;}void swap(string& s){std::swap(_str, s._str);std::swap(_capacity, s._capacity);std::swap(_size, s._size);}void clear(){_str[0] = '\0';_size = 0;}size_t find(char ch, size_t pos = 0) const{assert(pos < _size);for (size_t i = pos; i < _size; ++i){if (_str[i] == ch){return i;}}return npos;}size_t find(const string& s, size_t pos = 0) const{assert(pos < _size);char* p = strstr(_str + pos, s._str);if (p == nullptr){return npos;}return p - _str;}size_t find(const char* str, size_t pos = 0) const{assert(pos < _size);char* p = strstr(_str + pos, str);if (p == nullptr){return npos;}return p - _str;}string& operator+=(const char ch){push_back(ch);return *this;}string& operator+=(const string& s){push_back(s._str);return *this;}string& operator+=(const char* str){push_back(str);return *this;}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;}const char& operator[](size_t pos) const{assert(pos < _size);return _str[pos];}char& operator[](size_t pos){assert(pos < _size);return _str[pos];}bool operator>(const string& s) const{			return strcmp(_str, s._str) > 0;}bool operator==(const string& s) const{return strcmp(_str, s._str) == 0;}bool operator>=(const string& s) const{return	*this > s || *this == s;}bool operator<(const string& s) const{return	!(*this >= s);}bool operator<=(const string& s) const{return	!(*this > s);}bool operator!=(const string& s) const{return	!(*this == s);}size_t size() const{return _size;}size_t capacity() const{return _capacity;}const char* c_str() const{return _str;}~string(){delete[] _str;_capacity = _size = 0;}private:char* _str;size_t _size;size_t _capacity;static const size_t npos;};const size_t string::npos = -1;ostream& operator<<(ostream& out, const string& s){for (auto ch : s){out << ch;}return out;}istream& operator>>(istream& in, string& s){s.clear();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();}if (i != 0){buff[i] = '\0';s += buff;}return in;}
}

如有错误,欢迎在评论区指出

完.

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

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

相关文章

gRPC-第二代rpc服务

在如今云原生技术的大环境下&#xff0c;rpc服务作为最重要的互联网技术&#xff0c;蓬勃发展&#xff0c;诞生了许多知名基于rpc协议的框架&#xff0c;其中就有本文的主角gRPC技术。 一款高性能、开源的通用rpc框架 作者作为一名在JD实习的Cpper&#xff0c;经过一段时间的学…

(vue)适合后台管理系统开发的前端框架

(vue)适合后台管理系统开发的前端框架 1、D2admin 开源地址&#xff1a;https://github.com/d2-projects/d2-admin 文档地址&#xff1a;https://d2.pub/zh/doc/d2-admin/ 效果预览&#xff1a;https://d2.pub/d2-admin/preview/#/index 开源协议&#xff1a;MIT 2、vue-el…

计算机网络——概述

计算机网络——概述 计算机网络的定义互连网&#xff08;internet&#xff09;互联网&#xff08;Internet&#xff09;互联网基础结构发展的三个阶段第一个阶段——APPANET第二阶段——商业化和三级架构第三阶段——全球范围多层次的ISP结构 ISP的作用终端互联网的组成边缘部分…

嵌入式学习36-TCP要点及http协议

TCP发送文件的粘包问题 1. 例&#xff1a; 发端 1.flv-------->收端 1.flv csfga 2.解决 1. sleep&#xff08;1&#xff09; 延时发送 2.自…

服务器又被挖矿记录

写在前面 23年11月的时候我写过一篇记录服务器被挖矿的情况&#xff0c;点我查看。当时是在桌面看到了bash进程CPU占用异常发现了服务器被挖矿。 而过了几个月没想到又被攻击&#xff0c;这次比上次攻击手段要更高明点&#xff0c;在这记录下吧。 发现过程 服务器用的是4090…

【文档智能】再谈基于Transformer架构的文档智能理解方法论和相关数据集

前言 文档的智能解析与理解成为为知识管理的关键环节。特别是在处理扫描文档时&#xff0c;如何有效地理解和提取表单信息&#xff0c;成为了一个具有挑战性的问题。扫描文档的复杂性&#xff0c;包括其结构的多样性、非文本元素的融合以及手写与印刷内容的混合&#xff0c;都…

ai语音克隆:用AI大模型开发点亮你的创作天地!

在当今快速发展的科技时代&#xff0c;人工智能技术已经深入到我们生活的方方面面。AI语音克隆作为其中的一种应用&#xff0c;正在逐渐走进人们的视野&#xff0c;为人们的创作提供了全新的可能性。 人类创作的过程往往是一个灵感迸发、思绪飞扬的过程。但有时候&#xff0c;…

实现QT中qDebug()的日志重定向

背景&#xff1a; 在项目开发过程中&#xff0c;为了方便分析和排查问题&#xff0c;我们需要将原本输出到控制台的调试信息写入日志文件&#xff0c;进行持久化存储&#xff0c;还可以实现日志分级等。 日志输出格式&#xff1a; 我们需要的格式包括以下内容&#xff1a; 1.…

eclipse搭建java web项目

准备条件 eclipsejdk1.8 &#xff08;配置jdk环境&#xff09;apache-tomcat-8.5.97&#xff08;记住安装位置&#xff09; 一 点击完成 开始创建javaweb项目 import java.io.IOException; import java.io.PrintWriter;import javax.servlet.ServletException; import javax.s…

Neo4j安装 Linux:CentOS、openEuler 适配langchain应用RAG+知识图谱开发 适配昇腾910B

目录 Neo4j下载上传至服务器后进行解压运行安装JAVA再次运行在windows端打开网页导入数据 Neo4j下载 进入Neo4j官网下载页面 向下滑动找到 Graph Database Self-Managed 选择 社区版&#xff08;COMMUNITY&#xff09; 选择 Linux / Mac Executable Neo4j 5.17.0 (tar) 单机下…

Android Studio编译及调试知识

文章目录 Android Studio编译kotlin项目Android Studio编译Java和kotlin混合项目的过程gradle打印详细错误信息&#xff0c;类似这种工具的使用Android apk 从你的代码到APK打包的过程&#xff0c;APK安装到你的Android手机上的过程&#xff0c;最后安装好的形态&#xff0c;以…

【Kotlin】类和对象

1 前言 Kotlin 是面向对象编程语言&#xff0c;与 Java 语言类似&#xff0c;都有类、对象、属性、构造函数、成员函数&#xff0c;都有封装、继承、多态三大特性&#xff0c;不同点如下。 Java 有静态&#xff08;static&#xff09;代码块&#xff0c;Kotlin 没有&#xff1…

Python算法题集_搜索二维矩阵

Python算法题集_搜索二维矩阵 题74&#xff1a;搜索二维矩阵1. 示例说明2. 题目解析- 题意分解- 优化思路- 测量工具 3. 代码展开1) 标准求解【矩阵展开为列表二分法】2) 改进版一【行*列区间二分法】3) 改进版二【第三方模块】 4. 最优算法5. 相关资源 本文为Python算法题集之…

二分/树上第k短路,LeetCode2386. 找出数组的第 K 大和

一、题目 1、题目描述 给你一个整数数组 nums 和一个 正 整数 k 。你可以选择数组的任一 子序列 并且对其全部元素求和。 数组的 第 k 大和 定义为&#xff1a;可以获得的第 k 个 最大 子序列和&#xff08;子序列和允许出现重复&#xff09; 返回数组的 第 k 大和 。 子序列是…

OpenAI (ChatGPT)中国免费试用地址

GitHub - click33/chatgpt---mirror-station-summary: 汇总所有 chatgpt 镜像站&#xff0c;免费、付费、多模态、国内外大模型汇总等等 持续更新中…… 个人能力有限&#xff0c;搜集到的不多&#xff0c;求大家多多贡献啊&#xff01;众人拾柴火焰高&#xff01;汇总所有 cha…

如何转行成为产品经理?

转行NPDP也是很合适的一条发展路径&#xff0c;之后从事新产品开发相关工作~ 一、什么是NPDP&#xff1f; NPDP 是产品经理国际资格认证&#xff0c;美国产品开发与管理协会&#xff08;PDMA&#xff09;发起的&#xff0c;是目前国际公认的唯一的新产品开发专业认证&#xff…

arm架构服务器使用Virtual Machine Manager安装的kylin v10虚拟机

本文中使用Virtual Machine Manager安装kylin v10的虚拟机 新建虚拟机 新建虚拟机 选择镜像&#xff0c;下一步 设置内存和CPU&#xff0c;下一步 选择或创建自定义存储&#xff08;默认存储位置的磁盘空间可能不够用&#xff09; 点击管理&#xff0c;打开选择存储卷页…

15. C++泛型与符号重载

【泛型编程】 若多组类型不同的数据需要使用相同的代码处理&#xff0c;在C语言中需要编写多组代码分别处理&#xff0c;这样做显然太过繁琐&#xff0c;C增加了虚拟类型&#xff0c;使用虚拟类型可以实现一组代码处理多种类型的数据。 虚拟类型是暂时不确定的数据类型&#…

朗伯特球腔均匀光源积分球

均匀光源积分球&#xff0c;又称照度积分球或光度球、光通球&#xff0c;是光电测试中常用的一种工具。它是一个中空的球体&#xff0c;内壁涂有一层平整的漫反射材料&#xff0c;通常由金属或陶瓷制成。积分球的主要功能是收集光并将其作为散射光源或测量光源使用。 积分球的工…

LeetCode54:螺旋矩阵

题目描述 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 示例 解题思想 模拟 循环一圈 后 跳出循环的条件&#xff1a;左边界&#xff1e;右边界 或者 上边界 > 下边界 代码 class Solution { public:vect…