C++标准模板库 STL——string的使用以及模拟实现

前言

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

STL的六大组件
在这里插入图片描述

为什么学习string类?
C语言中,字符串是以’\0’结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。
在OJ中,有关字符串的题目基本以string类的形式出现,而且在常规工作中,为了简单、方便、快捷,基本都使用string类,很少有人去使用C库中的字符串操作函数。

目录

1.string类
2.string类的常用接口说明
3.模拟实现string

1.string类

  1. 字符串是表示字符序列的类
  2. 标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作
    单字节字符字符串的设计特性。
  3. string类是使用char(即作为它的字符类型,使用它的默认char_traits和分配器类型(关于模板的更多信
    息,请参阅basic_string)。
  4. string类是basic_string模板类的一个实例,它使用char来实例化basic_string模板类,并用char_traits
    和allocator作为basic_string的默认参数(根于更多的模板信息请参考basic_string)。
  5. 注意,这个类独立于所使用的编码来处理字节:如果用来处理多字节或变长字符(如UTF-8)的序列,这个
    类的所有成员(如长度或大小)以及它的迭代器,将仍然按照字节(而不是实际编码的字符)来操作。
    总结:
  6. string是表示字符串的字符串类
  7. 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
  8. string在底层实际是:basic_string模板类的别名,typedef basic_string<char, char_traits, allocator>string;
  9. 不能操作多字节或者变长字符的序列。
    在使用string类时,必须包含#include头文件以及using namespace std;

2.string 类的常用接口说明

2.1string类对象的常见构造

constructor功能说明
string()构造空的string 对象,即空字符串
string (const char * str)用C-string来构造string类对象
string(size_t n ,char c)string 类对象中包含n个字符c
string (const string& s)拷贝构造函数

代码测试

#include <iostream>
#include<string>
using namespace std;//string类的常用接口测试void test_string()
{string s1("");//空字符串cout << s1 << endl;string s2("hello world");//用C-string来构造string类对象cout << s2 << endl;string s3(8, '*');  //string 类对象中包含n个字符ccout << s3 << endl;string s4(s3);//拷贝构造函数cout << s4 << endl;
}int main()
{test_string();return 0;
}

在这里插入图片描述

2.2 string 类的容量操作

函数名称功能说明
size返回字符串有效字符长度
length返回字符串有效字符长度
capacity返回空间总大小
empty检测字符串释放为空串,是返回true,否则返回false
clear清空有效字符
reserve为字符串预留空间
resize将有效字符的个数该成n个,多出的空间用字符c填充
  1. size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()。

代码测试:

void test_string3()
{string s1;s1.resize(15, '*');cout << s1.size() << endl;cout << s1.length() << endl;cout << s1.capacity() << endl;cout << s1 << endl;s1.resize(20, '#');cout << s1.size() << endl;cout << s1.length() << endl;cout << s1.capacity() << endl;cout << s1 << endl;string s2;s2.resize(15, '&');cout << s2.size() << endl;cout << s2.length() << endl;cout << s2.capacity() << endl;cout << s2 << endl;s2[0]++;s2.at(0)++;cout << s2 << endl;
}

运行结果:
在这里插入图片描述

  1. clear()只是将string中有效字符清空,不改变底层空间大小。
    代码测试:
void test_stringClear()
{string s("hello world");cout << s << endl;s.clear();cout << s << endl;cout << s.size() << endl;cout << s.capacity() << endl;}

运行结果:
在这里插入图片描述

  1. resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。

代码测试:

void test_stringResize()
{string s1;s1.resize(15, '*');cout << s1.size() << endl;cout << s1.length() << endl;cout << s1.capacity() << endl;cout << s1 << endl;s1.resize(20, '#');cout << s1.size() << endl;cout << s1.length() << endl;cout << s1.capacity() << endl;cout << s1 << endl;string s2;s2.resize(15, '&');cout << s2.size() << endl;cout << s2.length() << endl;cout << s2.capacity() << endl;cout << s2 << endl;s2[0]++;s2.at(0)++;cout << s2 << endl;
}

运行结果:
在这里插入图片描述

  1. reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserver不会改变容量大小。

代码测试:

void test_stringReserve()
{string s;s.reserve(100);size_t old = s.capacity();cout << "初始:" << s.capacity() << endl;for (size_t i = 0; i < 100; i++){s.push_back('m');if (s.capacity() != old){cout << "扩容:" << s.capacity() << endl;old = s.capacity();}}s.reserve(10);cout << s.capacity() << endl;
}

运行结果:
在这里插入图片描述

2.3 string类对象的访问及遍历操作

函数名称功能说明
operator[ ]返回pos位置的字符,const string类对象调用
begin() , end()begin获取第一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器
rbegin(),rend()begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器
范围forC++11支持更简洁的范围for的新遍历方式

代码测试

void test_stringFor()
{string s1("hello world");string s2 = "hello world";for (size_t i = 0; i < s1.size(); i++){cout << s1[i];}cout << endl;string::reverse_iterator rit = s1.rbegin();while (rit != s1.rend()){cout << *rit << " ";rit++;}cout << endl;for (auto ch : s1){cout << ch << " ";}cout << endl;
}

运行结果:
在这里插入图片描述

2.4 string类对象的修改操作

函数名称功能说明
push_back在字符串后尾插字符c
append在字符串后追加一个字符串
operator+=在字符串后追加字符串str
c_str返回C格式字符串
find + npos从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置
rfind从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置
substr在str中从pos位置开始,截取n个字符,然后将其返回

代码测试

void test_string5()
{string s1("test.cpp.tar.zip");//size_t i = s1.find('.');size_t i = s1.rfind('.');string s2 = s1.substr(i);cout << s2 << endl;//string s3("https://legacy.cplusplus.com/reference/string/string/rfind/");string s3("https://cn.bing.com/search?pglt=41&q=baidu&cvid=b6332837d8f642d1befbdeeaae18733b&aqs=edge..69i57j0l8.1965j0j1&FORM=ANSPA1&PC=EDGEDBB");string s4;string s5;string s6;size_t j = s3.find(':');if (j != string::npos)s4 = s3.substr(0, j);elsecout << "没有找到" << endl;size_t m = s3.find('/', j + 3);if (m != string::npos)s5 = s3.substr(j + 3, m - (j + 3));elsecout << "没有找到" << endl;s6 = s3.substr(m);cout << s4 << endl;cout << s5 << endl;cout << s6 << endl;
}

运行结果:
在这里插入图片描述

3.模拟实现string

string.h

#pragma once
#include <assert.h>
namespace xiaobai
{class string{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;}char& operator[](size_t n){assert(n < _size);return _str[n];}const char& operator[](size_t n) const{assert(n < _size);return _str[n];}string(const char* str = ""):_size(strlen(str)), _capacity(_size){_str = new char[_capacity + 1];strcpy(_str, str);}~string(){delete[] _str;_str = nullptr;_size = _capacity = 0;}size_t capacity() const{return _capacity;}size_t size() const{return _size;}const char* c_str() const{return _str;}void reserve(size_t n){if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}}void push_back(char ch){if (_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size] = ch;_size++;_str[_size] = '\0';}void append(const char* str){size_t len = strlen(str);if (_size + len > _capacity){reserve(_size + len);}strcpy(_str + _size, str);_size += len;}string& operator+=(char ch){push_back(ch);return *this;}string& operator+=(const char* str){append(str);return *this;}// 在pos位置上插入字符c/字符串str,并返回该字符的位置string& insert(size_t pos, char c){assert(pos <= _size);if (_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}size_t end = _size + 1;while (end > pos){_str[end] = _str[end - 1];end--;}_str[pos] = c;_size++;return *this;}string& insert(size_t pos, const char* str){assert(pos <= _size);size_t len = strlen(str);size_t end = _size +len +1;if (end> _capacity){reserve(end);}while (end > pos){_str[end] = _str[end - strlen(str)-1];end--;}// 拷贝插入strncpy(_str + pos, str, len);_size += len;return *this;}string& erase(size_t pos, size_t len = npos){if (len == npos || pos + len >= _size)    //pos开始到结尾都要删除{_str[pos] = '\0';_size = pos;}else{memmove(_str + pos, _str + pos + len, len);_size -= len;}return *this;}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 strcmp(_str, s._str) == 0;}bool operator!=(const string& s) const{return (!(*this == s));}void clear(){_str[0] = '\0';_size = 0;}private:char* _str;size_t  _size;size_t _capacity;const static size_t npos;};const size_t string::npos = -1;ostream& operator<<(ostream& out, const string& str){for (auto ch : str){out << ch;}return out;}istream& operator>>(istream& in,string& str){str.clear();char ch;ch = in.get();str.reserve(128);while (ch != ' ' && ch != '\n'){if (str.size() == str.capacity()){str.reserve(str.capacity() * 2);}str += ch;}return in;}void test_string1(){string str1("hello world");cout << str1.c_str()<< endl;for (size_t i = 0; i < str1.size(); i++){cout << str1[i] << " ";}cout << endl;string::iterator it = str1.begin();while (it != str1.end()){cout << *it << " ";it++;}cout << endl;for (auto ch : str1){cout << ch << " ";}cout << endl;}void test_string2(){string s1("hello world");cout << s1.c_str() << endl;s1.push_back(' ');s1.append("hello bit");s1 += '#';s1 += "hello linux";cout << s1.c_str() << endl;}void test_string3(){string s1("hello bit!");cout<<s1.insert(5, '#')<<endl;cout << s1 << endl;cout << s1.insert(3, "hello xiaobai") << endl;cout << s1 << endl;cout<<s1.erase(2)<<endl;cout << s1 << endl;cout << (s1 > "hello world") << endl;cout << (s1 < "hello world") << endl;cout << (s1 <= "hello world") << endl;cout << (s1 >= "hello world") << endl;cout << (s1 == "hello world") << endl;cout << (s1 != "hello world") << endl;cout << s1.insert(1,'#')<<endl;cout << s1 << endl;}
}

test.cpp

#include<iostream>
#include<string>
#include<vector>
#include<list>using namespace std;
#include"string.h"int main()
{//xiaobai::test_string1();//xiaobai::test_string2();xiaobai::test_string3();return 0;
}

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

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

相关文章

电阻和电容

目录 1、常见的电阻器 2、电容 ​编辑 1、常见的电阻器 对于电阻需要了解三个参数&#xff08;查询电阻的数据手册&#xff09;&#xff1a; 1、封装&#xff1a;就是电阻的尺寸或者大小&#xff0c;看焊在你的pcb板上是否合适。 2、标称&#xff1a;电阻的电阻大小、精度、…

小程序分销机制介绍,小程序二级分销功能有哪些?

为什么有越来越多的用户选择使用小程序&#xff1f;跟“高大上”的APP相比&#xff0c;小程序不仅可以减少下载安装的复杂流程&#xff0c;还具备操作便捷、沉淀私域数据的优势。蚓链分销小程序具备裂变二维码、实时分佣、分销身份升级、层级分佣、商品个性化佣金设定等功能&am…

ARM+Codesys标准通用型控制器

整机工业级设计&#xff0c;通讯外设经过隔离保护 电源宽电压设计(9~36V DC ) 丰富的通讯接口&#xff0c;满足多种场合控制和通讯需求 四核工业级处理器&#xff0c;高性能&#xff0c;低功耗&#xff0c;高可靠性 机身无风扇设计&#xff0c;外壳小巧 搭载内核 100% 自主…

音频修复和增强工具 iZotope RX 10 for mac激活最新

iZotope RX 10是一款音频修复和增强软件&#xff0c;主要特点包括&#xff1a; 声音修复&#xff1a;iZotope RX 10可以去除不良噪音、杂音、吱吱声等&#xff0c;使音频变得更加清晰干净。音频增强&#xff1a;iZotope RX 10支持对音频进行音量调节、均衡器、压缩器、限制器等…

【YOLOv 剪枝 轻量化】融合YOLOv5s与通道剪枝算法的奶牛轻量化个体识别方法(英文版含中文翻译)

融合YOLOv5s与通道剪枝算法的奶牛轻量化个体识别方法 Light-weight recognition network for dairy cows based on the fusion of YOLOv5s and channel pruning algorithm 论文链接知网链接 DOI链接 引用格式&#xff1a; 许兴时&#xff0c;王云飞&#xff0c;华志新&#xf…

品牌为什么要做价格管控

价格管控的目的其实是为了治理低价&#xff0c;低价的存在会使渠道变得不可控&#xff0c;比如经销商低价跟价&#xff0c;消费者因为低价而转投其他品牌&#xff0c;这些无形中都会影响品牌的销量&#xff0c;阻碍品牌发展&#xff0c;所以做价格管控&#xff0c;就是在做好低…

count(*) 和 count(1) 有什么区别?哪个性能最好?

哪种 count 性能最好&#xff1f; count() 是什么&#xff1f; count() 是一个聚合函数&#xff0c;函数的参数不仅可以是字段名&#xff0c;也可以是其他任意表达式&#xff0c;该函数的作用是统计符合查询条件的记录中&#xff0c;函数指定的参数不为 NULL 的记录由多少条。…

电脑和手机查看ip地址

文章目录 看电脑 ip 地址查看手机 ip 地址浏览器访问网址获取ip&#xff08;电脑和手机都能用&#xff09; 看电脑 ip 地址 【方法一】 1、电脑右下角找到连接的网络 2、拉到最下面属性即可看到 IP 地址 在这里插入图片描述 【方法二】 1、Win R 然后输入 cmd 打开命令行 …

华为云云耀云服务器L实例评测|教你如何使用云服务器L实例

目录 一、为什么选择华为云云耀云服务器L实例1、智能不卡顿2、价优随心用3、上手更简单4、管理特省心 二、服务器快速上手1、注册账号2、查看华为云耀云服务器L实例产品信息3、购买4、查看服务器详情5、远程登录6、通过第三方终端连接 三、宝塔面板管理服务器 本篇文章给大家分…

Flutter 完美的验证码输入框 转载

刚开始看到这个功能的时候一定觉得so easy&#xff0c;开始的时候我也是这么觉得的&#xff0c;这还不简单&#xff0c;然而真正写的时候才发现并没有想象的那么简单。 先上图&#xff0c;不上图你们都不想看&#xff0c;我难啊&#xff0c;到Github&#xff1a; https://gith…

zemax优化功能

1、三种优化方法 zemax的三种优化方法中&#xff0c;局部优化会找到局部的极小值点&#xff0c;全局优化会找到整体的最小值点。 锤形优化适用于先用全局优化找到大概值后&#xff0c;进一步完善光学系统 对于评价函数单调或者局部最小值就是全局最小值的情况&#xff0c;使…

什么牌子的led台灯质量好?Led台灯品牌质量排行榜

台灯如何选择&#xff0c;随着人们生活水平的提高及科技的不断进步&#xff0c;台灯的品质也得到了极大的提高&#xff0c;在生活中很多时候都需要使用台灯&#xff0c;但是市面上的台灯那么多&#xff0c;台灯如何选择。推荐五款质量高的护眼台灯。 一、书客护眼台灯L1 书客…

Unity(三) Shader着色器初探

学习3D开发技术的时候无可避免的要接触到Shader&#xff0c;那么Shader是个什么概念呢&#xff1f;其实对于开发同事来说还是比较难理解的&#xff0c;一般来说Shader是服务于图形渲染的一类技术&#xff0c;开发人员可以通过其shader语言来自定义显卡渲染页面的算法&#xff0…

【Electron】electron与cljs的处理

实现效果: 前言&#xff1a; 如何用cljs的方式&#xff0c;编写electron应用&#xff0c;可以实现多窗体应用 要使用ClojureScript&#xff08;CLJS&#xff09;编写一个 Electron 应用程序&#xff0c;并实现多窗体功能&#xff0c;您可以按照以下步骤进行操作&#xff1a; …

【深度学习】 Python 和 NumPy 系列教程(二):Python基本数据类型:3、字符串(索引、切片、运算、格式化)

目录 一、前言 二、实验环境 三、Python基本数据类型 3. 字符串&#xff08;Strings&#xff09; 1. 初始化 2. 索引 3. 切片 4. 运算 a. 拼接运算 b. 复制运算 c. 子串判断 d. 取长度 5. 格式化 a. 使用位置参数 b. 使用关键字参数 c. 使用属性访问 f-string…

Qt 5.15集成Crypto++ 8.8.0(MSVC 2019)笔记

一、背景 笔者已介绍过在Qt 5.15.x中使用MinGW&#xff08;8.10版本&#xff09;编译并集成Crypto 8.8.0。 但是该编译出来的库&#xff08;.a和.dll&#xff09;不适用MSVC&#xff08;2019版本&#xff09;构建环境&#xff0c;需要重新编译&#xff08;.lib或和.dll&#xf…

分布式、锁、延时任务

1. redission redission 原理 Redis分布式锁-这一篇全了解(Redission实现分布式锁完美方案) 2.zk 2.1 指令 ls / / 下有哪些子节点 get /zookeeper 查看某个子节点内容 create /aa “test” delete /aa set /aa “test01” 2.2 创建节点 模式 默认创建永久 create -e …

redis(1)-hiredis-Windows下的编译

1.linux编译说明文档 GitHub - sewenew/redis-plus-plus: Redis client written in C 2.hiredis 编译 2.1 hiredis下载 https://github.com/redis/hiredis.git 2.2 hiredis cmake编译 2.2.1 配置生成:ConfigeGenerateOpen Project 配置源目录&#xff1a;…

【直接运行TS文件的三种方法】

直接运行TS文件的三种方法 文章目录 直接运行TS文件的三种方法法一&#xff1a;将 ts 编译成 js&#xff0c;然后运行 js 文件法二&#xff1a;用 ts-node 直接运行 ts法三&#xff1a;webstorm中直接运行ts(TypeScript) 法一&#xff1a;将 ts 编译成 js&#xff0c;然后运行 …

解决:AD装配输出拾放文件出现闪退问题

PCB在装配输出过程中&#xff0c;需要导出拾放文件&#xff0c;但是今天每次执行这个过程&#xff0c;AD软件就会直接闪退。 重启AD把项目管理器中没有关掉的一系列乱七八糟文件手动关闭关闭AD软件再次重启AD&#xff0c;打开项目重新导出。