C++ STL之string的使用及模拟实现

文章目录

  • 1. 前言
  • 2. 介绍
  • 3. string类的使用
    • 3.1 string类的构造函数
    • 3.2 string类对象的容量操作
    • 3.3 string类对象的访问及遍历操作
    • 3.4 string类对象的修改操作
    • 3.5 string类对象的字符串操作
    • 3.6 string类的非成员函数
  • 4. string类的模拟实现


1. 前言

C语言中,字符串是以'\0'结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合面向对象编程的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。所以C++引入了string类作为标准库中用于处理字符串的数据类型。string类封装了字符串的操作,提供了更方便、安全和高级的字符串处理功能,更符合面向对象编程的思想。

2. 介绍

英文解释:

在这里插入图片描述

简单来说:

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

3. string类的使用

3.1 string类的构造函数

(constructor)函数代码功能说明
string();(默认构造函数)构造一个空字符串,长度为零个字符。
string(const string& str);(拷贝构造函数)构造一个 str 的副本。
string (const string& str, size_t pos, size_t len = npos);(子串构造函数)拷贝 str 从字符位置 pos 开始,跨越 len 个字符(如果 str 太短或者 len 为string::npos,则复制直到 str 的末尾)。
string(const char* s);拷贝由 s 指向的以空字符结尾的字符序列(C 字符串)。
string (const char* s, size_t n);从由 s 指向的字符数组中拷贝前 n 个字符。
string(size_t n, char c);使用字符 c 连续填充字符串 n 次。
template <class InputIterator> string (InputIterator first, InputIterator last);拷贝迭代器区间[first, last)范围内的字符序列。

实例:

// string constructor
#include <iostream>
#include <string>int main()
{std::string s0("Initial string");// 按照上述描述的顺序使用的构造函数std::string s1;std::string s2(s0);std::string s3(s0, 8, 3);std::string s4("A character sequence");std::string s5("Another character sequence", 12);std::string s6a(10, 'x');std::string s6b(10, 42);      // 42 is the ASCII code for '*'std::string s7(s0.begin(), s0.begin() + 7);std::cout << "s1: " << s1 << "\ns2: " << s2 << "\ns3: " << s3;std::cout << "\ns4: " << s4 << "\ns5: " << s5 << "\ns6a: " << s6a;std::cout << "\ns6b: " << s6b << "\ns7: " << s7 << '\n';return 0;
}

输出结果:

在这里插入图片描述

3.2 string类对象的容量操作

函数名称代码功能说明
sizesize_t size() const;返回字符串有效字符长度。
lengthsize_t length() const;返回字符串有效字符长度。
max_sizesize_t max_size() const;返回字符串可以达到的最大长度。
resizevoid resize (size_t n);
void resize (size_t n, char c);
将字符串调整为长度为 n 的字符。如果 n 小于当前字符串的长度,当前值将缩短为其前 n 个字符,删除第 n 个字符之后的字符。如果 n 大于当前字符串的长度,当前内容将被扩展,插入足够数量的字符以达到大小为 n。如果指定了字符 c,则新元素将被初始化为 c 的副本,否则它们将是值初始化的字符(空字符)。
capacitysize_t capacity() const;以字节为单位,返回当前为字符串分配的存储空间的大小。
reservevoid reserve (size_t n = 0);请求将字符串的容量调整为计划更改的大小,最多达到长度为 n 的字符。如果 n 大于当前字符串的容量,该函数将导致容器增加其容量以容纳 n 个字符(或更多)。在所有其他情况下,它被视为非强制性请求来缩小字符串的容量:容器的实现可以自由优化,并保留容量大于 n 的字符串。该函数不会对字符串长度产生影响,也不能修改其内容。
clearvoid clear();清空有效字符。
emptybool empty() const;返回字符串是否为空(即长度是否为 0)。

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

函数名称代码功能说明
operator[]char& operator[] (size_t pos);
const char& operator[] (size_t pos) const;
返回字符串中位置 pos 处字符的引用。
atchar& at (size_t pos);
const char& at (size_t pos) const;
返回字符串中位置 pos 处字符的引用。该函数会自动检查 pos 是否是字符串中一个有效的字符位置(即,pos 是否小于字符串的长度),如果不是,则抛出 out_of_range 异常。
backchar& back();
const char& back() const;
返回字符串的最后一个字符的引用。该函数不应在空字符串上调用。
frontchar& front();
const char& front() const;
返回字符串的第一个字符的引用。

遍历操作

#include <iostream>
#include <string>int main()
{std::string str("Test string");// 1.普通下标遍历for (size_t i = 0; i < str.size(); ++i)std::cout << str[i];std::cout << '\n';// 2.迭代器遍历for (std::string::iterator it = str.begin(); it != str.end(); ++it)std::cout << *it;std::cout << '\n';// 3.范围for遍历for (auto e : str)std::cout << e;std::cout << '\n';return 0;
}

解释

  1. 普通下标遍历:
    在这个部分的代码中,使用了一个普通的for循环和下标操作符[]来遍历字符串中的字符。循环变量i从0开始递增,直到达到字符串的长度(通过str.size()获取)。在每次迭代中,使用str[i]来获取对应位置的字符,并使用std::cout打印出来。
  2. 迭代器遍历:
    这部分代码使用了迭代器来遍历字符串中的字符。通过调用str.begin()获取字符串的起始位置迭代器,并使用str.end()获取字符串的结束位置迭代器。然后,使用一个for循环和迭代器操作来遍历字符串中的每个字符。在每次迭代中,使用解引用操作符*来获取当前迭代器指向的字符,并使用std::cout打印出来。
  3. 范围for遍历:
    在这部分代码中,使用了范围for循环来遍历字符串中的字符。通过for (auto e : str)的语法,将字符串中的每个字符依次赋值给变量e。在每次迭代中,直接使用变量e来表示当前字符,并使用std::cout打印出来。

3.4 string类对象的修改操作

函数名称代码功能说明
operator+=string& operator+= (const string& str);
string& operator+= (const char* s);
string& operator+= (char c);
在字符串末尾追加字符串 str、C字符串 s 或字符 c。
appendstring& append (const string& str);在字符串后追加一个字符串 str。
push_backvoid push_back (char c);在字符串后尾插字符 c。
insertstring& insert (size_t pos, const string& str);在指定位置 pos 插入另一个字符串 str。
erasestring& erase (size_t pos = 0, size_t len = npos);从字符串的位置 pos 开始删除长度为 len 的字符(如果内容太短或者 len 为 string::npos,则直到字符串的末尾)。如果未提供 len 参数,则默认删除从位置 pos 开始到字符串末尾的所有字符(类似于成员函数 clear)。返回一个引用,指向当前字符串的修改后的对象。

3.5 string类对象的字符串操作

函数名称代码功能说明
c_strconst char* c_str() const;回一个指向以空字符结尾的字符序列(即 C 字符串)的指针,该字符序列表示当前字符串对象的值。
substrstring substr (size_t pos = 0, size_t len = npos) const;返回一个新构造的字符串对象,其值为当前对象的子串副本。子串是从字符位置 pos 开始的、长度为 len 的字符序列(或者直到字符串的末尾)。
findsize_t find (const string& str, size_t pos = 0) const;
size_t find (const char* s, size_t pos = 0) const;
在当前字符串的 pos 索引位置(默认为0)开始,查找子串 str(或C 字符串 s),返回找到的位置索引,-1表示查找不到子串。
rfindsize_t rfind (const string& str, size_t pos = npos) const;
size_t rfind (const char* s, size_t pos = npos) const;
在当前字符串的 pos 索引位置开始,反向查找子串 str(或C 字符串 s),返回找到的位置索引,-1表示查找不到子串。
find_first_ofsize_t find_first_of (const char* s, size_t pos = 0) const;在当前字符串的 pos 索引位置(默认为0)开始,在字符串中搜索与其参数中指定的任意字符匹配的第一个字符。
find_last_ofsize_t find_last_of (const char* s, size_t pos = npos) const;在当前字符串的 pos 索引位置(默认为0)开始,在字符串中搜索与其参数中指定的任意字符匹配的最后一个字符。
find_first_not_ofsize_t find_first_not_of (const char* s, size_t pos = 0) const;在当前字符串的 pos 索引位置开始,在字符串中搜索与其参数中指定的任意字符不匹配的第一个字符。
find_last_not_ofsize_t find_last_not_of (const char* s, size_t pos = npos) const;在当前字符串的 pos 索引位置开始,在字符串中搜索与其参数中指定的任意字符不匹配的最后一个字符。

3.6 string类的非成员函数

函数名称代码功能说明
operator+string operator+ (const string& lhs, const string& rhs);返回一个新构造的字符串对象,其值是将 lhs 的字符后跟 rhs 的字符连接而成。
operator>>istream& operator>> (istream& is, string& str);支持 cin 读入 string 类对象,遇到空格回车结束。
operator<<ostream& operator<< (ostream& os, const string& str);支持 cout 输出 string 类对象。
getlineistream& getline (istream& is, string& str);从输入流 is 中提取字符,并将它们存储到字符串 str 中,直到找到换行字符 ‘\n’。
relational operatorsoperator==
operator!=
operator<
operator<=
operator>
operator>=
支持比较操作符(==,!=,<,<=,>,>=)

说明

  • getline(cin, s)会获取前一个输入的换行符,需要在前面添加读取换行符的语句。如:getchar() cin.get()

    例如:

    int n;
    string s;
    cin >> n;
    getchar(); //cin.get()
    getline(cin, s); // 可正确读入下一行的输入
    
  • operator+尽量少用,因为传值返回,导致深拷贝效率低。

4. string类的模拟实现

// string.h 文件
#pragma once
#include <iostream>
#include <string.h>
#include <assert.h>
using namespace std;namespace my_string
{class string{friend ostream& operator<<(ostream& _cout, const my_string::string& s);friend istream& operator>>(istream& _cin, my_string::string& s);public:typedef char* iterator;typedef const char* const_iterator;public:string(const char* str = ""):_size(strlen(str)), _capacity(_size){_str = new char[_capacity + 1];strcpy(_str, str);}void swap(string& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}string(const string& s):_size(0), _capacity(0), _str(nullptr){string tmp(s._str);swap(tmp);}string& operator=(const string& s){if (this != &s){string tmp(s);swap(tmp);}return *this;}~string(){delete[] _str;_str = nullptr;_size = _capacity = 0;}iterator begin(){return _str;}iterator end(){return _str + _size;}const_iterator begin() const{return _str;}const_iterator end() const{return _str + _size;}size_t size()const{return _size;}size_t capacity()const{return _capacity;}bool empty()const{return _size;}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){if (n <= _size){_str[n] = '\0';_size = n;}else{reserve(n);while (_size < n){_str[_size] = c;++_size;}_str[_size] = '\0';}}void push_back(char c){if (_size == _capacity){reserve(_capacity == 0 ? 4 : 2 * _capacity);}_str[_size++] = c;_str[_size] = '\0';}string& operator+=(char c){push_back(c);return *this;}void append(const char* str){size_t len = strlen(str);if (len + _size > _capacity){reserve(len + _size);}strcpy(_str + _size, str);_size += len;}string& operator+=(const char* str){append(str);return *this;}string substr(size_t pos, size_t len){string s;size_t end = pos + len - 1;if (len == npos || pos + len >= _size){len = _size - pos;end = _size;}s.reserve(len);for (size_t i = pos; i <= end; i++){s += _str[i];}return s;}void clear(){_str[0] = '\0';_size = 0;}const char* c_str()const{return _str;}char& operator[](size_t index){assert(index < _size);return _str[index];}const char& operator[](size_t index)const{assert(index < _size);return _str[index];}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);}size_t find(char c, size_t pos) const{while (pos < _size){if (_str[pos] == c){return pos;}pos++;}return npos;}size_t find(const char* s, size_t pos) const{const char* p = strstr(_str + pos, s);if (p)return p - _str;elsereturn npos;}string& insert(size_t pos, char c){assert(pos <= _size);if (_size == _capacity){reserve(_capacity == 0 ? 4 : 2 * _capacity);}size_t end = _size + 1;while (end >= pos + 1){_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);if (len == 0)return *this;if (len + _size > _capacity){reserve(len + _size);}size_t end = _size + len;while (end >= pos + len){_str[end] = _str[end - len];--end;}strncpy(_str + pos, str, len);_size += len;return *this;}string& erase(size_t pos, size_t len){assert(pos < _size);if (len == npos || pos + len >= _size){_str[pos] = '\0';_size = pos;}else{size_t begin = pos + len;while (begin <= _size){_str[begin - len] = _str[begin];++begin;}_size -= len;}return *this;}private:char* _str;size_t _size;size_t _capacity;public:const static size_t npos;};ostream& operator<<(ostream& _cout, const my_string::string& s){for (auto e : s)_cout << e;return _cout;}istream& operator>>(istream& _cin, my_string::string& s){s.clear();char buff[129];size_t i = 0;char ch;ch = _cin.get();while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == 128){buff[i] = '\0';s += buff;i = 0;}ch = _cin.get();}if (i != 0){buff[i] = '\0';s += buff;}return _cin;}
};const size_t my_string::string::npos = -1;

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

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

相关文章

地图 - 实现有多条定位,显示多条定位,并且使用一个圆形遮罩层将多条定位进行覆盖

首先&#xff0c;需要在你的index.html模板页面头部加载百度地图JavaScript API代码&#xff0c;密钥可去百度地图开放平台官网申请 <script type"text/javascript" src"//api.map.baidu.com/api?typewebgl&v1.0&ak您的密钥"></script&…

代码随想录 Leetcode1047. 删除字符串中的所有相邻重复项

题目&#xff1a; 代码(首刷自解 2024年1月21日&#xff09;&#xff1a; class Solution { public:string removeDuplicates(string s) {if (s.size() < 2) return s;stack<char> t;for (int i 0; i < s.size(); i) {if (t.empty()) t.push(s[i]);else {if (s[i…

InnoDB的Buffer Pool

前置概念&#xff1a;一个数据页16KB&#xff0c;一个数据页可能有多个记录&#xff0c;即使我们只需要访问一条记录&#xff0c;需要把整个数据页加载到内存中&#xff0c;加载到内存后不是直接释放&#xff0c;而是缓存到内存当中&#xff08;当然对于buffer pool的缓存是在存…

若依管理系统搭建教程,ruoyi-vue环境搭建

环境部署 准备工作 JDK > 1.8 (推荐1.8版本) Mysql > 5.7.0 (推荐5.7版本) Maven > 3.0 运行系统 1、前往Gitee下载页面([https://gitee.com/y_project/RuoYi (opens new window)](https://gitee.com/y_project/RuoYi))下载解压到工作目录 2、导入到Eclipse&#…

ESP32-TCP服务端(Arduino)

将ESP32设置为TCP服务器 介绍 TCP&#xff08;Transmission Control Protocol&#xff09;传输控制协议&#xff0c;是一种面向连接的&#xff08;一个客户端对应一个服务端&#xff09;、可靠的传输层协议。在TCP的工作原理中&#xff0c;它会将消息或文件分解为更小的片段&a…

Day16 linuxC高级(存储类型 linux命令 shell命令)

文章目录 C补充标识常量存储类型1.auto // 自动型2.static&#xff1a;修饰变量和函数 // 静态型3.extern&#xff1a;外部引用4.register&#xff1a;寄存器类型 LinuxC高级简介&#xff1a;嵌入式系统(将软件嵌入到硬件里面)Linux起源查看操作系统版本内核系统架构系统关机或…

CSDN COC西安城市开发者社区2023年度线下聚会

1. 活动背景 CSDN始终致力于促进城市区域内尖端新型技术开发者交流&#xff0c;提供开放自由的切磋平台。在这个充满挑战和机遇的一年即将结束之际&#xff0c;通过本次聚会&#xff0c;汇聚西安本地各行各业的开发者朋友&#xff0c;回顾过去一年城市社区的成就和收获&#x…

Spring5系列学习文章分享---第一篇(概述+特点+IOC原理+IOC并操作之bean的XML管理操作)

目录 Spring&#xff08;概述特点IOC原理IOC并操作之bean的XML管理操作&#xff09;概述Spring是轻量级的开源的JavaEE框架Spring可以解决企业应用开发的复杂性Spring有两个核心部分ioc,aopSpring特点 loc(概念和原理)什么是 IOCIOC 底层原理IOC 过程图 IOC&#xff08;接口&am…

MySQL的一些综合运用

一些基本的语句&#xff1a; USE dept_emp; CREATE TABLE dept ( deptno INT(2) NOT NULL COMMENT 部门编号, dname VARCHAR (15) COMMENT 部门名称, loc VARCHAR (20) COMMENT 地理位置 ); -- 添加主键 ALTER TABLE dept ADD PRIMARY KEY (deptno); -- 添加数据 INSE…

前端转鸿蒙的就业前景如何?有必要学鸿蒙么?

学习鸿蒙开发是否有必要&#xff0c;取决于多个因素&#xff1a; 一、个人兴趣与职业规划&#xff1a; 如果你对华为鸿蒙操作系统&#xff08;HarmonyOS&#xff09;感兴趣&#xff0c;并且希望将这个平台作为你的职业发展的方向&#xff0c;那么学习鸿蒙开发是非常有意义的。…

MSG3D

论文在stgcn与sta-lstm基础上做的。下面讲一下里面的方法&#xff1a; 1.准备工作 符号。这里是对符号进行解释。 一个人体骨骼图被记为G(v,E) 图卷积&#xff1a; 图卷积定义 考虑一种常用于处理图像的标准卷积神经网络 (CNN)。输入是像素网格。每个像素都有一个数据值向…

x-cmd pkg | speedtest-cli - 网络速度测试工具

目录 简介首次用户功能特点竞品和相关作品进一步探索 简介 speedtest-cli 是一个网络速度测试工具&#xff0c;用于测试计算机或服务器与速度测试服务器之间的网络连接速度。 它使用 speedtest.net 测试互联网带宽&#xff0c;可以帮助用户获取网络的上传和下载速度、延迟等参…

【复现】SpringBlade SQL 注入漏洞_22

目录 一.概述 二 .漏洞影响 三.漏洞复现 1. 漏洞一&#xff1a; 四.修复建议&#xff1a; 五. 搜索语法&#xff1a; 六.免责声明 一.概述 SpringBlade 是由一个商业级项目升级优化而来的SpringCloud微服务架构&#xff0c;采用Java8 API重构了业务代码&#xff0c;完全…

【C++初阶】第二站:类与对象(上) -- 下部分

前言&#xff1a; 本章知识点&#xff1a; 类对象模型、 this 指针 专栏&#xff1a; C初阶 目录 类对象模型 如何计算类对象的大小 类对象的存储方式猜测 结构体内存对齐规则 this指针 this指针的引出 this指针的特性 C语言和C实现Stack的对比 C语言实现 C实现 类对象模型 …

动态规划——炮兵回城【集训笔记】

题目描述 游戏盘面是一个m行n列的方格矩阵&#xff0c;将每个方格用坐标表示&#xff0c;行坐标从下到上依次递增&#xff0c;列坐标从左至右依次递增&#xff0c;左下角方格的坐标为(1,1)&#xff0c;则右上角方格的坐标为(m,n)。 游戏结束盘上只剩下一枚炮兵没有回到城池中&a…

ERP系统哪个好用?用友,金蝶,ORACLE,SAP综合测评

ERP系统哪个好用&#xff1f;用友&#xff0c;金蝶&#xff0c;ORACLE&#xff0c;SAP综合测评 ERP领域SAP、ORACLE相对于国内厂商如用友、金蝶优势在哪&#xff1f; SAP&#xff0c;ORACLE操作习惯一般国人用不惯&#xff1b;相对于国产软件&#xff0c;界面也很难看&#x…

AlmaLinux 9.3 安装图解

风险告知 本人及本篇博文不为任何人及任何行为的任何风险承担责任&#xff0c;图解仅供参考&#xff0c;请悉知&#xff01;本次安装图解是在一个全新的演示环境下进行的&#xff0c;演示环境中没有任何有价值的数据&#xff0c;但这并不代表摆在你面前的环境也是如此。生产环境…

Android学习之路(22) 从模块化到组件化

从模块化到组件化 一、从模块化到组件化 Android 应用项目 , 都存在一个应用模块 ( Application Module ) , 在 build.gradle 构建脚本中 , 第一个插件配置 com.android.application , 表明 该 Module 编译打包后的输出是 APK 安装包 ; 该项目可以直接运行 ; plugins {id co…

React进阶 - 11( 说一说 PropTypes 和 DefaultProps )

本章内容 目录 PropTypesDefaultProps 截止到上一节的内容&#xff0c;我们使用了一个 TodoList的案例&#xff0c;大概了解了 React的一些入门知识。从本节内容开始&#xff0c;我们将进入React进阶知识的学习 PropTypes 在组件拆分时&#xff0c;我们知道每个组件都有自己的…

AI快速构建中文文本蕴含深度学习模型-NeuronBlocks(一)

案例介绍 随着自然语言处理(NLP)领域研究的不断深入&#xff0c;如何让机器能够真正地理解自然语言&#xff0c;而不是仅简单地处理语句的表层信息&#xff0c;渐渐成为了许多学者面临的问题。实现对文本深层次理解&#xff0c;是自然语言处理研究最主要也是最重要的目的之一。…