C++中string的用法总结+底层剖析

前言:在C语言中,我们经常使用字符串进行一系列操作,经常使用的函数如下:增删改查

(自己造轮子),C++中设计出string容器,STL库中为我们提供了以上函数,所以我们使用string容器时,就不用造轮子了

参考网站:https://legacy.cplusplus.com/reference/string/string/?kw=string

底层实现,这里我用的是VS的编译器(window)(简化版本),linux(g++)这里使用计数引用(这里不采用计数引用实现)

constructor(构造函数)

第一个(第四个):是无参构造

#include<string>
#include<iostream>
using namespace std;
int main()
{string s;return 0;
}

s中只含有'\0'(无参构造时)

底层实现:(运用全缺省构造)

string(const char* arr = "")
{int len = strlen(arr);_str = new char[len + 1];// '\0'要单独开空间strcpy(_str, arr);_size = len;_capacity = len;
}

第二个:拷贝构造(将 str 中的所有成员变量全部赋值给*this)

string(const string& s)
{_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;
}

第三个:将str中的字符串从下标为pos ,拷贝字符的个数为npos

(注意npos 为默然时,则为字符串能存储最多的个数,不是_capacity,而是系统默然能储存的最大值,此时npos = -1)

当npos > len - pos 时 , 就拷贝全部

举个例子:

destructor(析构函数)

~string()
{delete[] _str;_size = 0;_capacity = 0;
}

operator=(赋值重载)

​
string& operator=(const string& s)
{char* tmp = new char[s._capacity + 1];strcpy(tmp, s._str);_size = s._size;_capacity = s._capacity;delete[] _str;_str = tmp;return *this;
}
//现代写法
string& operator=(string s)
{swap(s);return *this;
}
​

现代写法含义:传参时,s进行拷贝构造,在交换*this与s

iterator(迭代器)

迭代器的行为像指针

范围for的原理就是迭代器

#include<string>
#include<iostream>
using namespace std;
int main()
{string s("0000000000000000000");string::iterator it = s.begin();while (it != s.end()){cout << *it << " ";it++;}cout << endl;
return 0;
}#include<string>
#include<iostream>
using namespace std;
int main()
{string s("0000000000000000000");for( auto e : s )cout << e << " ";cout << endl;return 0;
}

这两个代码等效,原理都是迭代器

//迭代器底层实现
char* begin()
{return _str;
}
char* end()
{return _str + _size;
}char* rbegin()
{return _str + _size;
}
char* rend()
{return _str;
}

capacity(容量)

_capacity当前开辟的空间最多能储存多少字符

_size代表当前有多少个有效的字符

库里面有提供查询_capacity,_size的函数

int size()
{
return _size;
}
int capacity()
{
return _capacity;
}

如何扩容:(库里面有两个函数,可以实现扩容)

第一个reserve

传入一个size_t的参数,作为要扩容到标准

当 n <= _capacity 一般不会造成缩容(这个要具体看编译器)

当 n > _capacity 会扩容

void reserve(size_t n = 0)
{if (n <= _capacity)return;else{char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}
}

第二个resize函数

当 n < _size 会造成有效数据的删除(有可能会缩容

当 n > _size 且n < _capacity 有可能会缩容,但会造成添加有效数据,一直到 n

当 n > _capacity 会造成扩容,并添加有效数据的个数,一直到 n 

void resize(size_t n, char c = '\0')
{if (n <= _size){_size = (int)n;_str[n] = '\0';}else{reserve(n);for (; _size < n; _size++){_str[_size] = c;}_str[_size] = '\0';// n为最多有效字符个数,_str[n] = '\0';}
}

clear函数

清空有效数据,令_size = 0;

empty函数

判断有效数据个数是否为0

operator[]

放回下标为pos的字符

char& operator[] (size_t pos)
{assert(pos < _size);return _str[pos];
}
const char& operator[] (size_t pos) const
{assert(pos < _size);return (const char )_str[pos];
}

需要assert(判断pos < _size ),防止对未进行赋值的位置解引用

operator+=(传入的是字符串也可以,因为会进行隐式类型转换)

string& operator+=(const string& s)
{if (s._size + _size > _capacity ){reserve(s._size + _size);}strcpy(_str + _size, s._str);_size += s._size;return *this;
}

在字符串末尾添加字符串

具体使用:与整形变量的使用方法一样

append(传入的是字符串也可以,因为会进行隐式类型转换)

string& append(const string& str)
{*this += str;//复用上面的+=return *this;
}

举个例子:

push_back

在字符串末尾添加一个字符

void push_back(char ch)
{if (_size == _capacity){reserve(_size * 2);}_str[_size++] = ch;_str[_size] = '\0';
}

assign(容量不改变)

第一个,第三个相当与拷贝构造

第二个就是将str中的字符串中的下标从subpos位置的sublen个字符,拷贝给*this

string& assign(const string& str, size_t subpos, size_t sublen)
{assert(_size - subpos >= sublen && sublen >= 0 );if (sublen > _capacity)reserve(sublen + _capacity);memcpy(_str, str._str + subpos, sublen);_size = sublen;_str[_size] = '\0';return *this;
}

第四个将s中的字符串前n个字符,给*this;

string& assign(const char* s, size_t n)
{if (n > _capacity)reserve(n);memcpy(_str, s, n);_size = n;_str[_size] = '\0';return *this;
}

第五个将n个字符c给*this

string& assign(size_t n, char c)
{if (n > _capacity)reserve(n);for (int i = 0; i < n; i++){_str[i] = c;}_size = n;_str[n] = '\0';return *this;
}

insert

请注意可以插入一个string

在pos位置前插入字符或字符串

string& insert(size_t pos, char c)
{
if( _capacity == _size )reserve( 2 * _size );for (size_t i = _size; i > pos; i--){_str[i] = _str[i - 1];}_size++;_str[pos] = c;
}string& insert(size_t pos, const char* str)
{int len = strlen(str);if (len + _size > _capacity)reserve(len + _size);for (size_t i = _size + len  ; i >= pos + len; i--){_str[i] = _str[i - len];}_size += len;memcpy(_str + pos, str, sizeof(char) * len);return *this;
}

使用方法:

自定义类型的变量 . insert ( 参数列表 )

erase

string& erase(size_t pos = 0, size_t len = npos)
{assert(pos >= 0);if (pos + len >= _size)_size = pos;else{for (size_t i = pos + len; i < _size; i++){_str[i - len] = _str[i];}_size -= len;}_str[_size] = '\0';return *this;
}

从下标为pos的位置,删除len个字符,其中当len == npos时,就将从pos位置起以后(包括pos位置的数据)的数据删除

find

size_t find(char c, size_t pos = 0) const
{for (size_t i = pos; i < _size; i++){if (_str[i] == c)return i;}return -1;//npos
}
size_t find(const char* s, size_t pos = 0) const
{char* tmp = strstr(_str , s );if (tmp == nullptr)return -1;else return tmp - _str;
}

找寻_str中是否存在字符c或字符串s,如果存在返回第一次出现时的下标

不存在,返回-1

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

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

相关文章

华为OD-C卷-密码解密[100分]Python3+C语言-90%

题目描述 给定一段“密文”字符串 s,其中字符都是经过“密码本”映射的,现需要将“密文”解密并输出。 映射的规则(a ~ i)分别用(1 ~ 9)表示;(j ~ z)分别用("10*" ~ "26*")表示。 约束:映射始终唯一。 输入描述 “密文”字符串 输出描述 …

libftdi1学习笔记 7 - MPSSE I2C

目录 1. 初始化 2. 原理 3. i2cStart 4. i2cStop 5. i2cRecvByte 6. i2cSendByte 7. i2cRead 8. i2cWrite 9. 验证 9.1 初始化i2c 9.2 初始化gpio 9.3 写10个字节到EEPROM 9.4 读回10字节数据 9.5 运行结果 I2C&#xff08;主&#xff09;采用2个或3个GPIO模拟的…

QTableView获取可见的行数

场景 当我们需要实时刷新QTableView时&#xff0c;而此时tableView的数据量较大&#xff0c;如果全部刷新显然不合理&#xff0c;如果可以只对用户看的到的数据进行刷新那就最好了&#xff0c;经过一番摸索找到了几种方式&#xff0c;可供参考 代码 方法1 QVector<int>…

64B/66B编码 自定义PHY层设计

一、前言 之前的一篇文章讲解了64B/66B的基本原理&#xff0c;本篇在基于64B/66B GT Transceiver的基础之上设计自定义PHY。基本框图如下。 二、GT Mdule GT Module就按照4个GT CHannel共享一个GT COMMON进行设置&#xff0c;如下图。要将例子工程中的GT COMMON取出&#xff…

docker环境搭建

项目环境搭建 1、安装 Linux 虚拟机 &#xff08;1&#xff09;下载安装&#xff1a; VM VirtualBox 下载安装&#xff1a;Downloads – Oracle VM VirtualBox&#xff0c;要先开启CPU虚拟化 &#xff08;2&#xff09;通过vagrant&#xff0c;在VirtualBox中安装虚拟机 下…

STM32学习和实践笔记(15):STM32中断系统

中断概念 CPU执行程序时&#xff0c;由于发生了某种随机的事件(外部或内部)&#xff0c;引起CPU暂 时中断正在运行的程序&#xff0c;转去执行一段特殊的服务程序(中断服务子程序 或中断处理程序)&#xff0c;以处理该事件&#xff0c;该事件处理完后又返回被中断的程序 继…

修改Ubuntu的镜像源为清华镜像源

修改Ubuntu的镜像源为清华镜像源 1、首先使用以下命令备份现有的镜像源&#xff1a; cd /etc/apt sudo cp sources.list sources.list.bak 2、使用以下命令打开镜像源文件&#xff1a; sudo vim /etc/apt/sources.list 3、在vim插入模式下使用以下内容替换掉原镜像源…

MySQL基础-----约束详解

目录 一. 概述: 二.约束演示&#xff1a; 三.外键约束&#xff1a; 3.1介绍&#xff1a; 3.2外键约束语法&#xff1a; 3.3删除&#xff0c;更新行为&#xff1a; 一. 概述: &#x1f9d0;&#x1f9d0;概念&#xff1a;约束是作用于表中字段上的规则&#xff0c;用于限制…

css面试题整理

css面试题 一、HTML语义化标签二、块级元素、内联元素、 行内块元素三、盒模型 一、HTML语义化标签 什么是HTML语义化标签&#xff1f;语义化标签的优势&#xff1f; HTML语义化标签顾名思义就是赋予标签含义&#xff0c;比如说<p>标签代表的是段落&#xff0c;还有<…

springboot结合vue实现文件上传下载功能

紧接着上一次的博客&#xff0c;这次来实现一下文件(主要是图片)的上传和下载功能&#xff0c;上一次的博客如下所示&#xff1a; Springboot集成JWT token实现权限验证-CSDN博客 其实文件的上传和下载功能(后端的部分)&#xff0c;在我之前的博客就已经有写了&#xff0c;所以…

区块链知识总结——智能合约

定义&#xff1a; 智能合约是一种基于区块链技术的自动化合约&#xff0c;它能够在没有第三方介入的情况下执行、管理和执行合约条款。智能合约是由代码编写的&#xff0c;存储在区块链上&#xff0c;并在满足特定条件时自动执行。 特点&#xff1a; 智能合约具有以下几个特…

LD-Pruner、EdgeFusion(On-Device T2I)、FreeDiff、TextCenGen、MemLLM

本文首发于公众号&#xff1a;机器感知 https://mp.weixin.qq.com/s/KiyNfwYWU-wBiCO-hE9qkA 苏 The devil is in the object boundary: towards annotation-free instance segmentation using Foundation Models Foundation models, pre-trained on a large amount of data…

AI技术与反诈的挑战

Sora的出现意味着今后利用AI升级技术实施欺诈行为门槛将变低&#xff0c;反欺诈产品服务类科技公司在面对更强大的欺诈攻击时&#xff0c;将面临更加严峻的挑战。其中&#xff0c;可预见最大的变化会来自“深度伪造”。“深度伪造”的危险不仅在于生成虚假视频和图片&#xff0…

# 从浅入深 学习 SpringCloud 微服务架构(三)注册中心 Eureka(1)

从浅入深 学习 SpringCloud 微服务架构&#xff08;三&#xff09;注册中心 Eureka&#xff08;1&#xff09; 段子手168 1、微服务的注册中心 注册中心可以说是微服务架构中的”通讯录”&#xff0c;它记录了服务和服务地址的映射关系。 在分布式架构中服务会注册到这里&am…

Docker使用教程及docker部署Vue项目

什么是Docker及其工作原理 虚拟化技术Docker是什么&#xff1f;三大基本术语核心算法原理和具体操作步骤 Docker和传统虚拟化技术区别为什么使用Docker&#xff1f;Docker有什么作用&#xff1f;1.解决应用部署的环境问题遇到问题达到效果 2.容器化 docker的各种命令解释运行机…

6.GodotCanvasItem、Node2D及自定义节点

CanvasItem节点 CanvasItem节点&#xff0c;CanvasItem -> Node&#xff0c;所以CanvasItem继承了Node的所有功能Canvas是画布的意思&#xff0c;所以CanvasItem代表了就是可以被绘制的节点&#xff0c;可以设置可视化界面和材质的颜色所有的2D节点和GUI节点都继承于CanvasI…

集成电路测试学习-2

3、电源电流&#xff08;IDD&#xff09; 目的 电源电流测试是指在额定电压条件下&#xff0c;通过电源消耗的电流来反映被测器件的功耗。 功耗对于一些电池驱动的设备&#xff0c;尤为重要&#xff0c;会直接影响产品的续航时间。 同时电源电流测试也是快速分辨被测器件好坏的…

网络行为分析与异常检测

构建防火墙和使用简单的安全解决方案不足以保护网络免受网络异常或攻击&#xff0c;因为DDoS攻击、未知恶意软件和其他安全威胁一直在上升&#xff0c;改变了网络安全格局。网络管理员必须积极主动地分析网络&#xff0c;获得对网络的完全控制&#xff0c;并全面了解网络流量活…

访问云平台中linux系统图形化界面,登录就出现黑屏的问题解决(ubuntu图形界面)

目录 一、问题-图形化界面访问黑屏 二、系统环境 &#xff08;一&#xff09;网络结构示意图 &#xff08;二&#xff09;内部机器版本 三、分析 四、解决过程 &#xff08;一&#xff09;通过MobaXterm远程访问图形化界面(未成功) 1、连接方法 2、连接结果 &#xf…

acwing-y总基础课算法笔记整理

技巧 vector, 变长数组&#xff0c;倍增的思想size() 返回元素个数 capacity() 容量empty() 返回是否为空clear() 清空front()/back()push_back()/pop_back()begin()/end()[]支持比较运算&#xff0c;按字典序pair<int, int>first, 第一个元素second, 第二个元素支持…