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,一经查实,立即删除!

相关文章

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;该事件处理完后又返回被中断的程序 继…

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;所以…

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…

# 从浅入深 学习 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…

网络行为分析与异常检测

构建防火墙和使用简单的安全解决方案不足以保护网络免受网络异常或攻击&#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, 第二个元素支持…

pt格式文件转engine小记【yolov5-6.0版本】

背景 项目是使用yolov5-6.0的版本&#xff0c;需要加一个新模型进去&#xff0c;yolov5提供的类别有很多&#xff0c;我这里使用chair椅子。第一步就是先把提供的pt文件转化为tensorrt所需要的engine格式的文件&#xff0c;在官网上有提供转换方法。&#xff08;似乎高版本的y…

查看apk是64位32位(三种方法)

通过检查APK文件&#xff0c;你可以确定该APK支持的架构类型&#xff0c;包括它是为64位&#xff08;例如arm64-v8a、x86_64&#xff09;还是32位&#xff08;例如armeabi-v7a、x86&#xff09;架构准备的。Android应用程序可以包含多个不同的二进制文件&#xff0c;每个文件针…

1097 矩阵行平移(语文题,选做)

输入样例&#xff1a; 7 2 99 11 87 23 67 20 75 89 37 94 27 91 63 50 11 44 38 50 26 40 26 24 73 85 63 28 62 18 68 15 83 27 97 88 25 43 23 78 98 20 30 81 99 77 36 48 59 25 34 22 输出样例&#xff1a; 529 481 479 263 417 342 343 样例解读 需要平移的是第 1、…

【Java】常见锁策略 CAS机制 锁优化策略

前言 在本文会详细介绍各种锁策略、CAS机制以及锁优化策略 不仅仅局限于Java&#xff0c;任何和锁相关的话题&#xff0c;都可能会涉及到下面的内容。 这些特性主要是给锁的实现者来参考的. 普通的程序猿也需要了解一些, 对于合理的使用锁也是有很大帮助的 文章目录 前言✍一、…

Spring Boot 2.x 将 logback 1.2.x 升级至 1.3.x

场景 安全部门针对代码进行漏洞扫描时&#xff0c;发现 logback-core 和 logback-classic 都属于 1.2.x 版本&#xff0c;这个版本存在 CVE 漏洞&#xff0c;并且建议升级到 1.3.x 版本。 问题 将两个包直接升级到 1.3.x 版本时&#xff0c;Spring Boot Web 服务启动直接出现…

CNN卷积神经网络之LeNet-5原理与实战

文章目录 CNN卷积神经网络之LeNet-5原理与实战1、LeNet-5网络结构&#xff1a;1.1、LeNet-5由两个部分组成&#xff1a;1.2、模型单元结构&#xff1a;1.3、数据的传输&#xff1a; 2、LeNet-5网络参数详解&#xff1a; CNN卷积神经网络之LeNet-5原理与实战 1、LeNet-5网络结构…