string的使用和模拟实现

💓博主个人主页:不是笨小孩👀
⏩专栏分类:数据结构与算法👀 C++👀 刷题专栏👀 C语言👀
🚚代码仓库:笨小孩的代码库👀
⏩社区:不是笨小孩👀
🌹欢迎大家三连关注,一起学习,一起进步!!💓

在这里插入图片描述

string

  • string的介绍
  • 结构
  • string的常用接口
    • 构造和析构
    • 遍历string
    • size和length
    • capacity
    • resize和reserve
    • 运算符重载
    • push_back和append
    • insert和erase
    • 查找
    • 截取字符串
    • 获取字符指针
    • 交换对象
    • 特殊读取

string的介绍

string是一个类,可以看成是一个用模板写的顺序表,它的底层结构和顺序表基本是一样的,一个字符指针和一个表示存储数据的个数的size,还有一个表示容量大小的capacity,我们知道C++需要兼容C语言,所以它的字符串后面也是需要有一个‘\0’,的但是size和capacity的大小是不包含这个‘\0’的,因此实际的容量要比capacity大一个。

  1. 字符串是表示字符序列的类。
  2. 标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作单字节字符字符串的设计特性。
  3. string类是使用char(即作为它的字符类型,使用它的默认char_traits和分配器类型。
  4. string类是basic_string模板类的一个实例,它使用char来实例化basic_string模板类,并用char_traits和allocator作为basic_string的默认参数。
  5. 注意,这个类独立于所使用的编码来处理字节:如果用来处理多字节或变长字符(如UTF-8)的序列,这个类的所有成员(如长度或大小)以及它的迭代器,将仍然按照字节(而不是实际编码的字符)来操作。

总结:

  1. string是表示字符串的字符串类。
  2. 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
  3. string在底层实际是:basic_string模板类的别名,typedef basic_string<char, char_traits, allocator> string;
  4. 不能操作多字节或者变长字符的序列。

结构

string的结构和顺序表很相似,一个存放字符的指针,还有一个标记个数的size,还有一个标记容量的capacity。

class
{private:char* _str;size_t _size;size_t _capacity;
}

string的常用接口

构造和析构

构造函数我们可以用个缺省参数,直接搞定无参和有参的情况,然后使用初始化列表把size和capacity给初始化一下,然后开个空间把参数拷贝过去就可以了。
析构函数的话很简单,直接释放空间即可,把其他值置一下0即可。

//构造
string(const char* s = ""): _size(strlen(s)), _capacity(_size)
{_str = new char[_capacity + 1];strcpy(_str, s);
}
//析构
~string()
{delete[] _str;_str = nullptr;_size = _capacity = 0;
}

遍历string

  1. 我们可以使用for循环来遍历
    在这里插入图片描述
    因为库里的string支持了[]运算符重载,我们可以就像遍历数组那样来遍历string。
int main()
{string s("123456");for (int i = 0; i < 6; i++){cout << s[i] << " ";}cout << endl;return 0;
}

因为它是传引用返回的,所以我们可读可写。它重载了一个const版本,所以当你传const对象时,就只能读不能写。

int main()
{string s("123456");for (int i = 0; i < 6; i++){s[i]++;}cout << s << endl;return 0;
}
  1. 使用迭代器遍历

迭代器我们可以理解为一个指针,然后需要一个范围,库里有几个函数,可以帮我们确定这个范围。

在这里插入图片描述
如果我们要正着遍历可以使用begin和end。

在这里插入图片描述
在这里插入图片描述
它的返回值是一个iterator的迭代器类型,然后这个类型在string类里面的,所以我们需要确定类域。

int main()
{string s("123456");string::iterator it = s.begin();while (it != s.end()){cout << *it << " ";it++;}cout << endl;return 0;
}

如果要倒着遍历,就需要使用了,rbegin和rend。
在这里插入图片描述
在这里插入图片描述
只不过他们的返回类型是reverse_iterator。

int main()
{string s("123456");string::reverse_iterator it = s.rbegin();while (it != s.rend()){cout << *it << " ";it++;}cout << endl;return 0;
}

这两对都是可读可写的,还剩两对前面带c的,是只能读,不能写。具体可戳标题详解。

  1. 使用范围for
int main()
{string s("123456");for (auto e : s){cout << e << " ";}cout << endl;return 0;
}

size和length

size和length的功能是一样的,都是返回字符串的长度,和C语言的strlen很相似。

在这里插入图片描述

在这里插入图片描述

int main()
{string s("123456");cout << s.size() << endl;cout << s.length() << endl;return 0;
}

capacity

capacity是返回已经开辟的容量的大小。

在这里插入图片描述

int main()
{string s("123456");cout << s.capacity() << endl;return 0;
}

模拟实现

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

resize和reserve

  1. resize

resize可以修改size的大小。

在这里插入图片描述
库里重载两个版本,resize分3个版本,它可能比capacity大,也可能在size和capacity中间,也有可能比size小。如果他比capacity大的话,会扩容,并且如果我们给字符参数,就会在我们原本的字符串后面全补我们给的那个字符,直到size变成我们设置的那个,我们没给字符的话,会补‘\0’,如果在size和capacity中间,不会扩容,但是还是会补充,如果比我们的size还小的话,就充当删除的功能了。

int main()
{string s("123456");s.resize(20);s.resize(20,'x');s.resize(10);s.resize(4);return 0;
}
  1. reserve

reserve可以设置capacity的大小,如果我们知道字符串多大的话,我们可以提前开好空间,因为让系统自己自动扩容的话,可能会频繁扩容,消耗太大了,所以我们在知道需要存储的字符串多大时可以提起开好空间。

在这里插入图片描述

int main()
{string s("123456");cout << s.capacity() << endl;s.reserve(100);cout << s.capacity() << endl;return 0;
}

模拟实现

void reserve(size_t n)
{if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}}
void resize(size_t n, char c = '\0')
{if (n <= _size){_str[n] = '\0';_size = n;}else{reserve(n);size_t begin = _size;_size = n;while (begin < n){_str[begin] = c;begin++;}_size = n;_str[begin] = '\0';}
}

运算符重载

  1. 赋值运算符

在这里插入图片描述

也就是说我们可以直接用string对象或者字符串来给新的对象赋值。

int main()
{string s;s = "123456";string s1("xxx");s = s1;return 0;
}
  1. +和+=

在这里插入图片描述

在这里插入图片描述

从这两张图我们就可以看出来,+=是成员函数,而+是全局函数。我们需要尾插是可以用+=也可以用+,但是+的代价是很大的,我们尽量使用+=。

int main()
{string  s("123");s += "456";s += '7';s = s + '8';return 0;
}

模拟实现

string& operator+=(const char s)
{push_back(s);return *this;
}string& operator+=(const char* s)
{append(s);return *this;
}
  1. 流插入和流提取
    在这里插入图片描述
    在这里插入图片描述

也就是说,我们可以直接使用cout和cin来对sting对象来进行输入和输出了。

模拟实现

  1. 流提取
    我们可以一个字符一个字符的提取,因为_str为私有的,我们无法访问,我们也可以使用友元,但是我们这里一个字符一个字符的访问。
ostream& operator<<(ostream& out, const string& s)
{int end = s.size();for (int i = 0; i < end; i++){out << s[i];}return out;
}
  1. 流插入

流插入也一样,我们一个字符一个字符的读,当读到‘\n’或者空格就停止,但是cin和scanf都无法读空格和换行,这是就需要一个函数,cin.get(),它的功能就和C语言的getcahr很相似。

在这里插入图片描述

istream& operator>>(istream& in, string& s)
{s.clear();char ch = in.get();while (ch != ' ' && ch != '\n'){s += ch;ch = in.get();}return in;
}
int main()
{string s;cin >> s;cout << s << endl;return 0;
}
  1. 比较运算符
    在这里插入图片描述
    我们可以直接使用比较运算符来对sting对象和字符串等进行比较了。

模拟实现

char& operator[](size_t pos)
{assert(pos < _size);return _str[pos];
}const char& operator[](size_t pos) const
{assert(pos < _size);return _str[pos];
}string& operator+=(const char s)
{push_back(s);return *this;
}string& operator+=(const char* s)
{append(s);return *this;
}bool operator<(const string& s)
{return strcmp(_str, s._str) < 0;
}bool operator==(const string& s)
{return strcmp(_str, s._str) == 0;
}bool operator<=(const string& s)
{return *this<s||*this==s;
}bool operator>(const string& s)
{return !(*this<=s);
}bool operator>=(const string& s)
{return !(*this<s);
}bool operator!=(const string& s)
{return !(*this==s);
}

push_back和append

  1. push_back
    在这里插入图片描述

尾插一个字符

  1. append
    在这里插入图片描述

尾插一段字符串,库里面给的接口很多,我们都不是很常用,我们都喜欢用+=。

模拟实现

void push_back(const char ch)
{if (_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size++] = ch;_str[_size] = '\0';}
void append(const char* s)
{size_t len = strlen(s);if (_size + len > _capacity){reserve(_size+len);}strcpy(_str + _size, s);_size += len;
}

insert和erase

  1. insert
    在这里插入图片描述

我们一般用的都是在某个位置插入一个字符或者字符串。

模拟实现

string& insert(size_t pos, char ch)
{assert(pos <= _size);if (_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}int end = _size;//必须强转,不然会类型提升,当pos=0时发生死循环while (end >= (int)pos){_str[end + 1] = _str[end];end--;}_str[pos] = ch;_size++;return *this;
}string& insert(size_t pos, const char* str)
{size_t len = strlen(str);if (_size + len > _capacity){reserve(_size + len);}int end = _size;while (end >= (int)pos){_str[end + len] = _str[end];end--;}strncpy(_str + pos, str, len);_size += len;return *this;
}
  1. erase
    在这里插入图片描述

删除某个位置的len个字符

模拟实现

earse我们需要提供一个npos的半缺省参数,如果不给的话就表示将pos以后得数据都删了。
nops是一个所有类都有的,所以我们可以定义为静态成员变量。

string& erase(size_t pos, size_t len = npos)
{assert(pos < _size);if (pos + len > _size || len == npos){_str[pos] = '\0';_size = pos;return *this;}else{size_t begin = pos + len;while (begin <= _size){_str[begin - len] = _str[begin];begin++;}_size -= len;return *this;}
}
public:const static int npos = -1;

查找

  1. find
    在这里插入图片描述
    我们可以用这个函数来查找字符串或者字符。
int main()
{string s("123456");int i = s.find("23");int j = s.find('5',2);int x = s.find("123", 2, 3);return 0;
}
  1. rfind
    在这里插入图片描述
    rfind也是查找只不过是从最后开始找。和find相似。

模拟实现

size_t find(char c, size_t pos = 0) const{assert(pos < _size);for (size_t i = pos; i < _size; i++){if (_str[i] == c){return i;}}return npos;}size_t find(const char* s, size_t pos = 0) const{size_t len = strlen(s);assert(pos + len < _size);char* str = strstr(_str + pos, s);if (str != nullptr){return str - _str;}return npos;}

截取字符串

substr
在这里插入图片描述

从pos位置开始提取len个字符,不给len直接取到最后。

模拟实现

string substr(size_t pos = 0, size_t len = npos) const
{string s;if (len == npos || pos + len > _size){size_t i = 0;for (i = pos; i <= _size; i++){s += _str[i];}return s;}else{size_t i = 0;for (i = pos; i < pos+len; i++){s += _str[i];}s += '\0';return s;}
}

获取字符指针

我们知道string是一个类,那我们想要得到底层的那个字符指针怎么获得呢?

我们可以使用c_str这个函数
在这里插入图片描述


int main()
{string s("123456");const char* str = s.c_str();return 0;
}

模拟实现

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

交换对象

swap
在这里插入图片描述

对于string有一个专门的swap,可以用来交换两个string对象。

int main()
{string s("123456");string s1("12");s.swap(s1);cout << s << endl << s1 << endl;return 0;
}

模拟实现

void swap(string& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}

特殊读取

我们知道cin和scanf一样,遇到空格或者换行都会提前结束,那我们需要读取的字符串包含空格或者换行怎么办呢,这时候就需要getline了。

在这里插入图片描述

int main()
{string s;getline(cin, s);cout << s;return 0;
}

我们也可以自己指定读取结束的字符。

今天的分享就到这里,感谢大家的关注和支持。

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

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

相关文章

Pytorch从零开始实战02

Pytorch从零开始实战——彩色图像识别 本系列来源于365天深度学习训练营 原作者K同学 文章目录 Pytorch从零开始实战——彩色图像识别环境准备数据集模型选择模型训练数据可视化 环境准备 本文基于Jupyter notebook&#xff0c;使用Python3.8&#xff0c;Pytorch2.0.1cu118…

Day 01 web前端基础知识

首先我们要了解什么事前端&#xff1f; 先简单用文字介绍一下&#xff1a; 一、入门知识 Web前端是指网站或应用程序的用户界面部分。它包括HTML、CSS、JavaScript等语言和技术&#xff0c;用于创建用户可浏览和交互的网页。Web前端的特点在于其交互性和动态性&#xff0c;可…

非常详细的trunk-based分支管理流程配置及使用

非常详细的trunk-based分支管理流程配置及使用。 目前业界主流的版本管理流程是Gitflow 和 trunk-based。 Gitflow流行的比较早。但是目前的流行度要低于 trunk-based模式工作流。trunk-based模式被誉为是现代化持续集成的最佳实践。 他俩的核心区别是,Gitflow是一个更严格…

如何优化你的Vue.js应用以获得最佳性能

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

vue3+ts+uniapp小程序封装获取授权hook函数

vue3tsuniapp小程序封装获取授权hook函数 小程序授权的时候&#xff0c;如果点击拒绝授权&#xff0c;然后就再也不会出现授权了&#xff0c;除非用户手动去右上角…设置打开 通过uni官方api自己封装一个全局的提示: uni.getSetting :http://uniapp.dcloud.io/api/other/settin…

前端综合练手小项目

导读 本篇文章主要以小项目的方式展开&#xff0c;其中给出的代码中均包含详细地注释&#xff0c;大家可以参照理解。下面4个小项目中均包含有 HTML、CSS、JavaScript 等相关知识&#xff0c;可以拿来练手&#xff0c;系统提升一下自己的前端开发能力。 废话少说&#xff0c;…

《Envoy 代理:云原生时代的流量管理》

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f405;&#x1f43e;猫头虎建议程序员必备技术栈一览表&#x1f4d6;&#xff1a; &#x1f6e0;️ 全栈技术 Full Stack: &#x1f4da…

SCRUM产品负责人(CSPO)认证培训课程

课程简介 Scrum是目前运用最为广泛的敏捷开发方法&#xff0c;是一个轻量级的项目管理和产品研发管理框架。产品负责人是Scrum的三个角色之一&#xff0c;产品负责人在Scrum产品开发当中扮演舵手的角色&#xff0c;他决定产品的愿景、路线图以及投资回报&#xff0c;他需要回答…

微服务如何改变软件开发:实战经验与最佳实践分享

文章目录 什么是微服务&#xff1f;微服务实战经验1. 定义明确的服务边界2. 使用API网关3. 自动化部署和持续集成4. 监控和日志记录 微服务最佳实践1. 文档和通信2. 弹性设计3. 安全性4. 版本控制5. 监控和警报 微服务的未来 &#x1f389;欢迎来到架构设计专栏~微服务如何改变…

C++版本的OpenCV实现二维图像的卷积定理(通过傅里叶变换实现二维图像的卷积过程,附代码!!)

C版本的OpenCV库实现二维图像的卷积定理过程详解 前言一、卷积定理简单介绍二、不同卷积过程对应的傅里叶变换过程1、“Same”卷积2、“Full”卷积3、“Valid”卷积 三、基于OpenCV库实现的二维图像卷积定理四、基于FFTW库实现的二维图像卷积定理五、总结与讨论 前言 工作中用…

计算机视觉--距离变换算法的实战应用

前言&#xff1a; Hello大家好&#xff0c;我是Dream。 计算机视觉CV是人工智能一个非常重要的领域。 在本次的距离变换任务中&#xff0c;我们将使用D4距离度量方法来对图像进行处理。通过这次实验&#xff0c;我们可以更好地理解距离度量在计算机视觉中的应用。希望大家对计算…

QML android 采集手机传感器数据 并通过udp 发送

利用 qt 开发 安卓 app &#xff0c;采集手机传感器数据 并通过udp 发送 #ifndef UDPLINK_H #define UDPLINK_H#include <QObject> #include <QUdpSocket> #include <QHostAddress>class UdpLink : public QObject {Q_OBJECT public:explicit UdpLink(QObjec…

C#,数值计算——Hashfn1的计算方法与源程序

1 文本格式 using System; using System.Collections; using System.Collections.Generic; namespace Legalsoft.Truffer { public class Hashfn1 { private Ranhash hasher { get; set; } new Ranhash(); private int n { get; set; } public Hash…

【C++11保姆级教程】列表初始化(Literal types)和委派构造函数(delegating))

文章目录 前言一、列表初始化 (List Initialization)1.1数组初始化1.2结构体初始化1.3容器初始化1.4列表初始化的优势 二、委派构造函数 (Delegating Constructors)2.1委派构造函数是什么&#xff1f;2.2委派构造函数示例代码2.3调用顺序2.3委派构造函数优势 总结 前言 C11引入…

SpringCLoud——Nacos配置中心

Nacos实现配置管理 统一配置管理 配置更新热更新 统一配置的创建是在UI界面中完成的&#xff1a; 首先我们点击【配置管理】然后点击【配置列表】&#xff1a; 然后我们就看到了配置管理界面&#xff0c;但是此时这里是空的&#xff0c;我们可以创建一些配置文件&#xff1a…

Springboot 实践(17)spring boot整合Nacos配置中心

前文我们讲解了Nacos服务端的下载安装&#xff0c;本文我们降价spring boot整合nacos&#xff0c;实现Nacos服务器配置参数的访问。 一、启动Nacos服务&#xff0c;创建三个配置文件&#xff0c;如下所示 Springboot-Nacos-Client-dev.yaml文件配置参数 Springboot-Nacos-Clie…

微信小程序自动化发布

参考:https://developers.weixin.qq.com/miniprogram/dev/devtools/ci.html 参考:https://www.npmjs.com/package/miniprogram-ci npm install miniprogram-ci -S上传文件 xx.js const isNodeJs typeof process ! undefined && process.release ! null &&…

智能文本纠错API的应用与工作原理解析

引言 在数字时代&#xff0c;文本撰写和传播变得日益重要&#xff0c;无论是在学校里写论文、在职场中发送邮件&#xff0c;还是在社交媒体上发表观点。然而&#xff0c;文字错误、标点符号错误、语法问题和不当的表达常常会削弱文本的质量&#xff0c;降低信息传达的效果。为…

数据结构-leetcode-数组形式的整数加法

解题图解&#xff1a; 下面是代码&#xff1a; /*** Note: The returned array must be malloced, assume caller calls free().*/ int* addToArrayForm(int* num, int numSize, int k, int* returnSize){int k_tem k;int klen0;while(k_tem){//看看k有几位k_tem /10;klen;}i…

第三节:在WORD为应用主窗口下关闭EXCEL的操作(2)

【分享成果&#xff0c;随喜正能量】凡事好坏&#xff0c;多半自作自受&#xff0c;既不是神为我们安排&#xff0c;也不是天意偏私袒护。业力之前&#xff0c;机会均等&#xff0c;毫无特殊例外&#xff1b;好坏与否&#xff0c;端看自己是否能应机把握&#xff0c;随缘得度。…