C++ string
目录
- string类介绍
- 访问:
- [ ] 遍历
- 迭代器遍历
- 范围for遍历
- 容量相关:
- 修改相关:
- 编码表的了解
- 写时拷贝的了解
- string的模拟
STL(standard template libaray-标准模板库):是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架。
string类介绍
string属于标准库,因为它的产生比stl早一些
C++为了避免跟c语言库冲突,头文件不带.h
string可以管理字符数组
求长度不能用strlen,strlen不能对自定义对象使用,而且自定义对象里面的内置类型的私有成员也不能随便访问,不同编译器下私有成员名字可能不一样。

平时用string没有用模板,实际上它是模板,只是库typedef过,因为大多数情况用的都是char,所以就实例化了

1、4是常用的构造,2是拷贝构造,3是用str对象的一部分去构造,5是用str的前n个初始化,6是用n个字符c去初始化,7可以用迭代区间去初始化

npos是string里的静态成员变量,类型是size_t, -1类型提升,全1的无符号是整形的最大值

string s1;string s2("hello");cin >> s1;cout << s1 << endl;cout << s2 << endl;//char str[1600];对比c语言,c++按需申请使用会更方便//scanf()//想拼接两个string的话string ret1 = s1 + s1;cout << ret1 << endl;//和字符串相加也可以string ret2 = s1 + "你好";cout << ret2 << endl;//相比于c语言中的strcat可读性会更好,而且strcat也不能扩容//strcat得找'\0',string中有size(),可以直接找到结尾
string s1("hello world");
string s2 = "hello world";
两种带参构造都可以用
用常量字符串初始化
第一种是构造
第二种是构造+拷贝构造,单参数的构造函数支持隐式类型转换
访问:
[ ] 遍历

// 遍历stringfor (size_t i = 0; i < s1.size(); i++){// 读cout << s1[i] << " ";}cout << endl;for (size_t i = 0; i < s1.size(); i++){// 写s1[i]++;}cout << s1 << endl;
at是一个函数跟[ ] 重载 不同的是at失败后(比如越界)会抛异常,[]是断言,会终止程序。

s2[0]++;
s2.at(0)++;
[]用起来会更直观
迭代器遍历
迭代器是遍历数据结构的一种方式,目前可以想象成指针,因为使用起来很像
每个数据结构的迭代器都是在类里面定义(或typedef)的,属于这个类域
// 迭代器string::iterator it = s1.begin();//while (it < s1.end()) //这里可以但是不建议,因为如果是别的数据结构就不支持了,比如listwhile (it != s1.end()) // 推荐玩法,通用{// 读cout << *it << " ";++it;}cout << endl;it = s1.begin();while (it != s1.end()){// 写*it = 'a';++it;}cout << endl;cout << s1 << endl;

[ ]用起来方便但不是每个数据结构都能用,它针对底层是连续的物理空间的数据结构,迭代器才是通用的方式
迭代器屏蔽了底层细节,很好体现了c++的封装


cbegin这些是想把const iterator区分出来,但其实还是直接用begin就好


普通的iterator支持读和写,const iterator只能读
const对象要调用const版本的begin,const版本begin返回const的迭代器
所以迭代器要和s.begin()返回一致
void func(const string& s)
{//string::const_iterator it = s.begin();auto it = s.begin();while (it != s.end()){// 不支持写// *it = 'a';// 读cout << *it << " ";++it;}cout << endl;//string::const_reverse_iterator rit = s.rbegin();auto rit = s.rbegin();while (rit != s.rend()){cout << *rit << " ";++rit;}cout << endl;
}void test_string4()
{string s1("hello worldxxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyy");func(s1);
}
范围for遍历
// 原理:编译器编译器替换成迭代器// 读for (auto ch : s1){cout << ch << " ";}cout << endl;// 写for (auto& ch : s1)//ch相当于*it的拷贝,所以加&才能修改{ch++;}cout << endl;cout << s1 << endl;
容量相关:
size和length


string的产生比stl早,所以当时用的是length
size 具有通用性
‘\0’标识结束,size不算’\0’
动态增长的数组还需要’\0’是因为要兼容c语言
让string能和c的接口结合起来
string filename;cin >> filename;FILE* fout = fopen(filename.c_str(), "r");

clear清除数据,stl没有严格规定是否释放空间,一般是不会释放的,因为清掉之后可能还要继续插入数据
max_size本意是想告诉我们string最长有多长,不同平台下实现不同,它是写死的,在我们内存不够时告诉我们也开不了。所以基本用不上。
扩容是怎么扩的?
void test_string6()
{string s;size_t old = s.capacity();cout << "初始" << s.capacity() << endl;for (size_t i = 0; i < 100; i++){s.push_back('x');if (s.capacity() != old){cout << "扩容:" << s.capacity() << endl;old = s.capacity();}}
}

在vs上我们会发现string s,它没有存数据,容量居然是15,也就是16的空间,这是因为开了一个16字节的数组
小于16,字符串存到buff数组里面
大于等于16,存在_str指向的空间,buff里面的空间就不要了
这是为了避免系统频繁开小块内存而引发内存碎片
平时string也比较小
_buff[16]_str_size_capacity
reserve和resize

g++下要100就会给100,vs2019下要100会给111
可以提前开空间,减少扩容,提高效率
stl没有规定reserve能不能减少空间,一般实现是不会减的(比如g++和vs)

不给c默认是给’\0’

让size变到n
修改相关:
插入单个字符

插入字符串

//用的多的也就3和1string ss("world");string s;s.push_back('#');s.append("hello");s.append(ss);cout<<s<< endl;


s += '#';s += "hello";s += ss;cout << s << endl;string ret1 = ss + '#';string ret2 = ss + "hello";cout << ret1 << endl;cout << ret2 << endl;
+的效率会较低(拷贝构造再传值返回),尽量用+=

assign,赋值,会把原来的数据覆盖
std::string str("xxxxxxx");
std::string base = "The quick brown fox jumps over a lazy dog.";str.assign(base);
std::cout << str << '\n';

insert/erase/repalce能不用就尽量不用,因为他们都涉及挪动数据,效率不高
接口设计复杂繁多,需要时查一下文档即可

string中swap的有效使用场景
空格替换为20%
std::string s2("The quick brown fox jumps over a lazy dog.");
string s3;for (auto ch : s2){if (ch != ' '){s3 += ch;}else{s3 += "20%";}}

模板的swap代价太高,string全局函数还提供了一个swap,所以就不会调用模板的swap
find系列
find从字符串pos位置开始往后找字符c
rfind从字符串pos位置开始往前找字符c
substr找子串:从pos位置开始,截取n个字符,然后返回

void test_string11()
{//string s3("https://legacy.cplusplus.com/reference/string/string/rfind/");string s3("ftp://www.baidu.com/?tn=65081411_1_oem_dg");// 协议// 域名// 资源名string sub1, sub2, sub3;size_t i1 = s3.find(':');if (i1 != string::npos)sub1 = s3.substr(0, i1);elsecout << "没有找到i1" << endl;size_t i2 = s3.find('/', i1+3);if (i2 != string::npos)sub2 = s3.substr(i1+3, i2-(i1+3));elsecout << "没有找到i2" << endl;sub3 = s3.substr(i2 + 1);cout << sub1 << endl;cout << sub2 << endl;cout << sub3 << endl;
}
编码表的了解
string为什么设计成模板?
内存中不能存a、b、c这种概念,内存中只有01,只能组合成值,值和符号之间要有联系就要建立一一映射的关系,这就是编码表
每个国家都需要一套编码表
我们的文字很多,一个字节一个汉字是不够表示的(8个bit有2^8个值)

各个国家文字数量的不同
主要有三类方案 UTF-8、UTF-16、UTF-32
这是国际上的,为了更好表示中文,我们也有自己的一份编码表比如GBK。

兼容ascll,常用的汉字用两个字节(110 10)编,相对生僻的用三个字节(110 10 10)编,特别生僻的用四个字节编


假设一段文字是用UTF-8写的,然后改成另外一个编码,查的时候对不上,就会出现乱码(存储格式和解释方式对应不上)
我们有时候会出现烫烫烫烫烫是因为数组没有初始化的时候是随机值,这个随机值是1开头被解释成汉字,查编码表正好是烫,取决于编译器用的是什么编码。
写时拷贝的了解



string的模拟
vs下:在类里定义静态成员变量时发现在类里可以定义的特例
const static size_t npos = -1;//针对const 静态的 整形类型开了一个特例
const static double npos = 1.1; //double就不行了
#include<iostream>
#include<assert.h>
using namespace std;namespace st
{class string{public:typedef char* iterator;typedef const char* const_iterator;string(const char* str = ""):_size(strlen(str)), _capacity(_size){_str = new char[_capacity + 1];strcpy(_str, str);}//string(const string& str)//{// _str = new char[str._capacity + 1];// strcpy(_str, str._str);// _size = str._size;// _capacity = str._capacity;//}//简化后string(const string& str):_str(nullptr),_size(0),_capacity(0){string tmp(str._str);//进构造swap(tmp);//this里的数据可能是随机值,如果把随机值跟tmp交换,//然后tmp出作用域之后调用析构,会把随机值空间释放,所以需要初始化_str}~string(){delete[] _str;_str = nullptr;_size = _capacity = 0;}/*string& operator=(const string& s){char*tmp = new char[s._capacity + 1];strcpy(tmp, s._str);delete[] _str;_str = tmp;_size = s._size;_capacity = s._capacity;return *this;}*//*string& operator=(const string& s){string tmp(s);swap(tmp);return *this;}*///简化后//写好拷贝构造就相当于写好了赋值string& operator=(string tmp){swap(tmp);return *this;}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 pos){assert(pos < _size);return _str[pos];}size_t size() const{return _size;}size_t capacity() const{return _capacity;}const char* c_str()const{return _str;}void resize(size_t n, char c = '\0'){if (n <= _size){_str[n] = '\0';_size = n;}else{reserve(n);while (_size < n){_str[_size++] = c;}}_str[_size] = '\0';}void reserve(int n){if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[]_str;_str = tmp;_capacity = n;}}void push_back(char c){assert(_size <= _capacity);if (_size == _capacity){reserve(_capacity == 0 ? 4 : 2 * _capacity);}_str[_size] = c;_size++;_str[_size] = '\0';}void append(const char* s){int len = strlen(s);if (len + _size > _capacity){reserve(len + _size);}strcpy(_str + _size, s);_size += len;}string& operator+=(char c){push_back(c);return *this;}string& operator+=(const char* s){append(s);return *this;}bool empty()const{return _size == _capacity;}bool operator>(const string& str)const{for (int i = 0; i < str.size(); i++){if (i == this->size())return true;if (this->_str[i] > str._str[i])return true;else if (this->_str[i] < str._str[i])return false;}return false;}bool operator==(const string& str)const{for (int i = 0; i < str.size(); i++){if (i == this->size() || this->_str[i] != str._str[i])return false;}return true;}bool operator<(const string& str)const{return !(*this >= str);}bool operator>=(const string& str)const{return *this > str || *this == str;}bool operator<=(const string& str)const{return *this < str || *this == str;}bool operator!=(const string& str)const{return !(*this == str);}size_t find(char c, size_t pos = 0)const{for (int i = pos; i < (*this).size(); i++){if ((*this)._str[i] == c){return i;}}return -1;}size_t find(const char* s, size_t pos = 0)const{char* str = strstr(_str + pos, s);return str == nullptr ? -1 : str - _str;}string substr(size_t pos, size_t len = npos){string s;size_t end = len+pos;if (len == npos || pos + len >= _size){len = _size - pos;end = _size;}s.reserve(len);while (pos < end){s += _str[pos];pos++;}return s;}string& insert(size_t pos, char c){if (_size == _capacity){reserve(_capacity == 0 ? 4 : 2 * _capacity);}for (int i = size(); i > pos; i--){_str[i] = _str[i - 1];}_str[pos] = c;_size++;_str[_size] = '\0';return *this;}string& insert(size_t pos, const char* str){int len = strlen(str);if (len + _size > _capacity){reserve(len + _size);}_size += len;for (int i = size(); i >= pos+len; i--){_str[i-1] = _str[i - len - 1];}for (int i = 0; i < len; i++){_str[i + pos] = str[i];}_str[_size] = '\0';return *this;}string& erase(size_t pos, size_t len = string::npos){if (len == npos || pos+len >= size()){_str[pos] = '\0';_size = pos;return *this;}for (size_t i = pos + len; i <=size(); i++){_str[i - len] = _str[i];}_size -= len;return *this;}void clear(){_str[0] = '\0';_size = 0;}void swap(string& s){char* str = s._str;size_t size = s._size;size_t capacity = s._capacity;s._str = _str;s._size = _size;s._capacity = _capacity;_str = str;_size = size;_capacity = capacity;}private:char* _str;size_t _size;size_t _capacity;public:const static size_t npos;};const size_t string::npos = -1;ostream& operator<<(ostream& out, const string& s){for (auto ch : s){out << ch;}return out;}istream& operator>>(istream& in, string& s){s.clear();char buff[129];int i = 0;char ch;ch=in.get();while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == 128){buff[i] = '\0';s += buff;i = 0;}ch = in.get();}if (i != 128){buff[i] = '\0';s += buff;}return in;}
}
相关文章:
C++ string
目录 string类介绍访问:[ ] 遍历迭代器遍历范围for遍历 容量相关:修改相关:编码表的了解写时拷贝的了解string的模拟 STL(standard template libaray-标准模板库):是C标准库的重要组成部分,不仅是一个可复用的组件库&a…...
百亿级访问量,如何做缓存架构设计
说在前面 在40岁老架构师 尼恩的读者社区(50)中,最近有小伙伴拿到了一线互联网企业如阿里、网易、有赞、希音、百度、网易、滴滴的面试资格,遇到一几个很重要的面试题:: 分布式缓存系统,如何架构?百亿级访…...
(数字图像处理MATLAB+Python)第十一章图像描述与分析-第三、四节:几何表述和形状描述
文章目录 一:几何描述(1)像素间几何关系A:邻接与连通B:距离 (2)像素间几何特征A:位置B:方向C:尺寸 (3)程序 二:形状描述&a…...
20230901工作心得:IDEA列操作lambda表达式加强版用法
今天是中小学开学时间,亦是9月的开始,继续努力。 今日收获较大的有四个地方,先说这四点。 1、IDEA列操作 使用场景:需要批量将Excel表格里的数据插入到数据库中,此时需要写大量的insert SQL语句。 比如像这样的&am…...
macOS Sonoma 14beta 7(23A5337a)更新发布,附黑/白苹果系统镜像
系统介绍(镜像请前往黑果魏叔官网下载) 黑果魏叔8 月 31 日消息,苹果今日向 Mac 电脑用户推送了 macOS 14 开发者预览版 Beta 7 更新(内部版本号:23A5337a),本次更新距离上次发布隔了 8 天。 …...
QT基础教程之九Qt文件系统
QT基础教程之九Qt文件系统 文件操作是应用程序必不可少的部分。Qt 作为一个通用开发库,提供了跨平台的文件操作能力。Qt 通过QIODevice提供了对 I/O 设备的抽象,这些设备具有读写字节块的能力。下面是 I/O 设备的类图(Qt5)&#…...
OpenCV(十八):图像直方图
目录 1.直方图统计 2.直方图均衡化 3.直方图匹配 1.直方图统计 直方图统计是一种用于分析图像或数据的统计方法,它通过统计每个数值或像素值的频率分布来了解数据的分布情况。 在OpenCV中,可以使用函数cv::calcHist()来计算图像的直方图。 calcHist(…...
mac pro 查看隐藏文件夹
在Mac上查看隐藏文件夹可以使用以下方法: 使用终端: 打开终端应用程序,位于“应用程序”文件夹的“实用工具”子文件夹中。 在终端中,输入以下命令,然后按回车键: defaults write com.apple.finder AppleS…...
软件测试/测试开发丨Selenium 高级定位 Xpath
点此获取更多相关资料 本文为霍格沃兹测试开发学社学员学习笔记分享 原文链接:https://ceshiren.com/t/topic/27036 一、xpath 基本概念 XPATH是一门在XML文档中查找信息的语言 XPATH使用路径表达式在XML文档中进行导航 XPATH的应用非常广泛,可以用于UI自…...
各类注意力机制Attention——可变形注意力
目录 《Attention is all you need 》稀疏Attention残差Attention通道注意力空间注意力时间注意力可变形注意力 《Attention is all you need 》 稀疏Attention 残差Attention 通道注意力 空间注意力 时间注意力 实际上序列类任务也属于时间注意力,比如transformer…...
桥接模式:连接抽象与实现
欢迎来到设计模式系列的第八篇文章!在之前的几篇文章中,我们已经学习了许多常见的设计模式,今天我们将继续探讨另一个重要的设计模式——桥接模式。 桥接模式简介 桥接模式是一种结构型设计模式,它主要用于将抽象部分与实现部分…...
同步推送?苹果计划本月推出 iOS17和iPadOS17,你的手机支持吗?
据报道,苹果公司计划在本月推出 iOS 17 和 iPadOS 17 正式版更新。与去年不同的是,这次更新将同时发布,而不是分别发布。根据彭博社的一位消息人士马克・古尔曼的说法,苹果公司认为 iOS 17 和 iPadOS 17 的第八个测试版已经非常接…...
方案展示 | RK3588开发板Linux双摄同显方案
iTOP-RK3588开发板使用手册更新,后续资料会不断更新,不断完善,帮助用户快速入门,大大提升研发速度。 RK3588开发板载4路MIPI CAMERA摄像头接口、MIPI CSI DPHY的4.5Gbps、2.5Gops的MIPI CSI CPHY,四路同时输入…...
数据库-多表设计
概述: 项目开发中,在进行数据库表结构设计时,会根据业务需求及业务模块之间的关系,分析并设计表结构,由于业务之间相互关联,所以各个表结构之间也存在着各种联系,基本分为三种: 一对…...
一个简单的文件系统(MinixFS)实现解析
1. Minix文件系统概要 Minix file system 是 Andrew S. Tanenbaum 在 1980 年代发明的文件系统, 并随着 Minix 操作系统一起于 1987 年发布。 Linus 编写 Linux 内核第一个版本的时候, 使用的也是 Minix FS, Linux 至今依然提供了对 Minix FS 的支持。Minix FS 结构简单, 易于…...
地图投影-2亚当斯方形
说明 亚当斯方形 II 投影显示了一个方形的世界。它是 Oscar S. Adams 于 1925 年提出的两种投影之一。该投影为等角投影,但方形的四个角除外。在 Adams 最初的设计中,该投影将赤道和中央经线显示为方形的对角线。 此投影的一个有利属性是可以进行细分或…...
atcoder库中类欧(类欧几里得算法)floor_sum用法
https://atcoder.jp/contests/practice2/tasks/practice2_c 求 ∑ i 0 N − 1 f l o o r ( ( A i B ) / m ) \sum_{i 0}^{N - 1} floor((A \times i B) / m) ∑i0N−1floor((AiB)/m) 直接使用即可: ansfloor_sum(n, m, A, B); //注意顺序...
后端面试话术集锦第 十一 篇:mybatis面试话术
这是后端面试集锦第十一篇博文——mybatis面试话术❗❗❗ 1. 介绍下mybatis,说说它的优缺点是什么? Mybatis是一个半ORM(对象关系映射)的持久层框架,它内部封装了JDBC,开发时只需要关注SQL语句本身,不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程…...
SpringBoot运维实用篇、打包、运行、高级配置、多环境开发、日志
文章目录 SpringBoot运维实用篇YW-1.SpringBoot程序的打包与运行程序打包程序运行SpringBoot程序打包失败处理命令行启动常见问题及解决方案SpringBoot项目快速启动(Linux版) YW-2.配置高级YW-2-1.临时属性设置YW-2-2.配置文件分类YW-2-3.自定义配置文件…...
springdoc-openapi-ui 整合 knife,多模块分组,脚手架
pom文件: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.o…...
未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?
编辑:陈萍萍的公主一点人工一点智能 未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战,在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...
SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...
【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解
JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用,结合SQLite数据库实现联系人管理功能,并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能,同时可以最小化到系统…...
无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...
【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论
路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中(图1): mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...
【JavaSE】多线程基础学习笔记
多线程基础 -线程相关概念 程序(Program) 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存…...
C语言中提供的第三方库之哈希表实现
一. 简介 前面一篇文章简单学习了C语言中第三方库(uthash库)提供对哈希表的操作,文章如下: C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...
