*C++:string

一.STL简介

1.STL

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

2.STL六大组件

二.标准库里的string类

标准string库网址:string - C++ Reference

1.string构造函数

int main()
{string s1;string s2("张三");string s3("hello world");string s4(10, '*');       //10个*string s5(s2);            //拷贝构造string s6(s3, 0, 5);      //以s3为基准,拷贝第0到第5个字符string s7(s3, 6);         //第三个参数没有给的时候会自动填充一个npos(-1),指向最后一个位置string s8(s3, 6, 100);    //超出string长度的时候,会以最后一个位置为结尾cout << s1 << endl;cout << s2 << endl;cout << s3 << endl;cout << s4 << endl;cout << s5 << endl;cout << s6 << endl;cout << s7 << endl;cout << s8 << endl;
}

2.赋值运算符重载(operator=)

int main()
{string s1;string s2("张三");s1 = s2;             //strcout << s1 << endl;s1 = "1111";         //char*cout << s1 << endl; s1 = '2';            //charcout << s1 << endl;return 0;
}

大于小于号运算符重载:

cout << (s1 == s2) << endl; //0
cout << (s1 > s2) << endl;  //0

3.string尾插(字符,字符串)

(1).尾插一个字符(push_back)

int main()
{string s1("hello");// 尾插一个字符s1.push_back('7');    //hello7
}
(2).尾插一个字符串(append,+=)

不过在一些情况下+=是更好的选择:

int main()
{// 增string s1("hello");// 尾插一个字符s1.push_back('7');// 尾插一个字符串s1.append("world");//    +=s1 += '7';                //本质上+=字符就是调用push_backs1 += "world";            //本质上+=字符串就是调用append
}

4.迭代器(iterator)

对于一个字符串,在C语言中我们使用下标+[ ],在C++的string里面,我们可以使用迭代器来实现字符串的遍历。

在这之前,我们先学会begin()和end()的使用方法:

所以实际上,这两个东西就是返回一个指向字符串起始/末尾字符的迭代器。

C语言遍历string的方法:

int main()
{string s1("hello world");cout << s1 << endl;// 遍历stringcout << s1.size() << endl;   //不包括\0// 下标+[]for (size_t i = 0; i < s1.size(); i++){cout << s1[i] << " ";}
}

C++可以使用迭代器来实现遍历:

int main()
{string s1("hello world");cout << s1 << endl;//迭代器string::iterator it = s1.begin();while (it != s1.end()){// 写(*it)--;++it;}cout << endl;it = s1.begin();while (it != s1.end()){// 读cout << *it << " ";++it;}cout << endl;
}

上面是正向迭代器,还有一个反向迭代器reverse_iterator,如果需要的是只读的对象,还可以有const_iterator和const_reverse_iterator。

范围for

相比于迭代器,范围for的迭代方式往往更加简洁:

int main()
{string s1("hello world");// 范围for   应用范围更广   //缺点:只能正向遍历,不能反向遍历// 底层替换为迭代器//for (char& ch : s1)for (auto& ch : s1){// 写 ch--;}cout << endl;for (char ch : s1){// 读cout << ch << " ";}cout << endl;return 0;
}

5.内存相关函数和扩容机制

(1).内存相关函数
int main()
{string s1("hello world");cout << s1.size() << endl;cout << s1.length() << endl;     //size 和 length本质上是一样的,推荐使用sizecout << s1.max_size() << endl;   //最大长度(没啥用)cout << s1.capacity() << endl;     //已开辟的空间大小(不同类型的编译器结果是不一样的)
}

clear()函数可以用来清空string,但是只能清空size,清空不了capacity,因为可能后续还会使用所以不会清理。

int main()
{cout << s1.size() << endl;cout << s1.capacity() << endl;s1.clear();     //clear只清理size,不清理capacitycout << s1.size() << endl;cout << s1.capacity() << endl;
}

reserve

reserve会开一块空间,vs会比给定的空间多扩容一点,XSell按实际开辟。

改变开辟空间的大小需要先清理数据,直接reserve不会起作用。

void TestPushBackReserve()
{string s;s.reserve(100);   //这里就是提前开好了空间,后续不再进行改变 //vs实际开出来的大小会比100(给出来的数)大   XShell就是按照实际的开辟   原则就是必须比给的数大size_t sc = s.size();size_t sz = s.capacity();cout << "capacity changed: " << sc << '\n';cout << "capacity changed: " << sz << '\n';cout << "making s grow:\n";for (int i = 0; i < 100; ++i){s.push_back('c');if (sz != s.capacity()){sz = s.capacity();cout << "capacity changed: " << sz << '\n';}}//想要改变空间大小需要先clear(),然后再设置新的空间大小s.clear(); cout << "capacity changed: " << sz << '\n';s.reserve(10);   //不清数据是不改变的sz = s.capacity();cout << "capacity changed: " << sz << '\n';
}// reserve // 保留
// reverse // 反转
int main()
{TestPushBackReserve();return 0;
}
resize
int main()
{string s1("hello world");// 开空间s1.reserve(100);cout << s1.size() << endl;//11cout << s1.capacity() << endl;//111// 开空间+填值初始化s1.resize(200);   //resize是对开辟出来的空间的200个对象初始化占用size大小,reserve比要求的的多一点s1.resize(200, 'x'); //hello worldxxxxxxxxxxxxxxxxxxxxxxxx...  如果空间大于原本,先进行扩容然后再填值初始化cout << s1.size() << endl;//200cout << s1.capacity() << endl;//207s1.resize(5);   //如果小于size的长度,则缩小显示个数,但是不会缩容  //hellocout << s1.size() << endl;//5cout << s1.capacity() << endl;//207s1.clear();   //可以把s1里面的内容给清除(size归0),但是空间不会在clear()函数上清除(capacity不归0)s1.resize(0);cout << s1.size() << endl;//0cout << s1.capacity() << endl;//207//没啥用,可以不记s1.shrink_to_fit();    //这个函数名义上是把s1空间调整至合适的大小,但实际上空间大小还是会比实际稍微大一点点cout << s1.size() << endl;//0cout << s1.capacity() << endl;//15//目前缩容的唯一办法:调用clear()函数后重新reservereturn 0;
}
(2).扩容机制(vs)
int main()
{string s1("hello world");size_t old = s1.capacity();for (size_t i = 0; i < 100; i++){s1 += 'x';//vs扩容机制:除第一次是原本的两倍,剩下的都是上一次容量的1.5倍//XShell是二倍扩容if (old != s1.capacity()) {cout << "扩容:" << s1.capacity() << endl;old = s1.capacity();	}}
}

6.at和错误分析

(1).at

有个引用符号,说明是可以修改的(下面会输出xello world)

int main()
{try {string s1("hello world");s1.at(0) = 'x';cout << s1 << endl;//s1[15];  // 暴力处理s1.at(15); // 温和的错误处理}catch (const exception& e){cout << e.what() << endl;}return 0;
}
(2).错误分析

如上图,类似于try-catch这样的就是一个错误检查,比如我们用s1.at(15);这是一个温柔检查,会抛出一个异常(即进入catch),如果直接用s1[15]会直接中断,因为[]是有强制性的,它是决不允许越界访问的。

s1.at(15);

s1[15];

7.插入删除

(1).insert

int main()
{string s1;s1.insert(0, "hello");  //在第几个位置插入cout << s1 << endl;s1.insert(5, "world");cout << s1 << endl;s1.insert(0, 10, 'x');  //第0开始插入10个xcout << s1 << endl;s1.insert(s1.begin()+10, 10, 'y');cout << s1 << endl;return 0;
}

(2).erase

int main()
{string s1("hello world");s1.erase(5, 1);   //如果类似于(5,7)超出了界限,则直接把后面的删掉,不会报错cout << s1 << endl;s1.erase(5);    //从第5个位置开始后面的全删掉cout << s1 << endl;try{s1.erase(11);   //如果位置超了,会抛出一个异常cout << s1 << endl;}catch (const exception& e){cout << e.what() << endl;}string s2("hello world");s2.erase(0, 1);cout << s2 << endl;s2.erase(s2.begin());cout << s2 << endl;return 0;
}

其中要注意,s.erase()对应的作用,s1.erase(5);是传入了一个范围,s2.erase(s2.begin());是传入了一个指向具体位置的迭代器。所以前者为删除一串数据,后者是删除一个确定的元素。

(3).replace

int main()
{// world替换成 xxxxxxxxxxxxxxxxxxxxxxstring s1("hello world hello bit");s1.replace(6, 5, "xxxxxxxxxxxxxxxxxxxxxx");   //第6个位置起的5个字符,替换成xxxxxxxxxxxxxxxxxxxxxxcout << s1 << endl;//replace没有缺省值s1.replace(6, 23, "yyyyy");cout << s1 << endl;// 所有空格替换成20%string s2("hello world hello bit");string s3;for (auto ch : s2){if (ch != ' '){s3 += ch;}else{s3 += "20%";}}s2 = s3;cout << s2 << endl;           //string的流插入重载cout << s2.c_str() << endl;   //本质上是调用的底层的private里的char* strreturn 0;
}

8.查找

(1).find


int main()
{string url = "ftp://www.baidu.com/?tn=65081411_1_oem_dg";// 协议:ftp// 域名:www.baidu.com// 资源名:?tn=65081411_1_oem_dgsize_t pos1 = url.find("://");//会返回第一个匹配项的第一个字符的位置。且不给第二个参数的情况下,默认从第一个字符开始找//如果没有相匹配的字符,返回string::npos  (-1)//请注意,与成员find_first_of不同,每当搜索多个字符时,仅匹配其中一个字符是不够的,整个序列都必须匹配。cout << pos1 << endl;string protocol;if (pos1 != string::npos){protocol = url.substr(0, pos1);    //子串,把第一个参数的位置到第二个参数的位置提取出来}cout << protocol << endl;string domain;string uri;size_t pos2 = url.find('/', pos1 + 3);if (pos2 != string::npos){domain = url.substr(pos1 + 3, pos2 - (pos1 + 3));uri = url.substr(pos2 + 1);}cout << domain << endl;cout << uri << endl;//rfind 从后往前找的return 0;
}

*  substr

str 中从 pos 位置开始,截取 n 个字符,然后将其返回
(2).find_first_of

int main()
{string url = "ftp://www.baidu.com/?tn=65081411_1_oem_dg";size_t pos1 = url.find_first_of(":&/");cout << pos1 << endl;return 0;
}

(size_t pos1 = url.find_first_of(":&/");)

如果是用的find,会返回-1,这就是find和find_first_of的区别。find与成员find_first_of不同,每当搜索多个字符时,仅匹配其中一个字符是不够的,整个序列都必须匹配。

(size_t pos1 = url.find(":&/");)

9.例题

. - 力扣(LeetCode). - 备战技术面试?力扣提供海量技术面试资源,帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。icon-default.png?t=O83Ahttps://leetcode.cn/problems/add-strings/description/

class Solution {
public:string addStrings(string num1, string num2) {int end1 = num1.size()-1;int end2 = num2.size()-1;string strRet;int carry = 0;//只要还有数,就得接着算,所以用或while(end1 >= 0 || end2 >= 0) {//没有数的进来只能置0,有数的进来置其距离'0'字符的距离(即实际数字)int val1 = end1 >= 0 ? num1[end1] - '0' : 0;int val2 = end2 >= 0 ? num2[end2] - '0' : 0;int ret = val1 + val2 + carry;carry = ret / 10;ret = ret % 10;strRet.insert(strRet.begin(), ret + '0');--end1;--end2;}if(carry == 1){strRet.insert(strRet.begin(), '1');}return strRet;}
};

三.vs下string结构说明

首先看下面一个例子:

int main()
{std::string s1("hello world");std::string s3("hello worldxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");cout << sizeof(s1) << endl;  cout << sizeof(s3) << endl;return 0;
}

我们可以看到对应的sizeof结果都是40,他具体是怎么存储的呢?进入调试:

可以看到,string有一个buf数组,字符串的内容保存在这个buf数组里。

但是对于s3,他的数据不在buf数组里:

可以看到string存在于_ptr指向的堆空间中。

由此可见:size<16,存在数组中;size>=16,存在_ptr指向的堆空间中。
作用:提供buf数组能提高效率,不过当size较大时会导致buf这块空间没有被使用浪费,不过这样的浪费是可以原谅的,相当于用空间换时间。

四.string类模拟实现

五.深浅拷贝及写时拷贝

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

朴世龙团队《Global Change Biology 》研究成果!揭示生物累积效应对秋季叶片衰老的重要调节作用!

本文首发于“生态学者”微信公众号&#xff01; 在全球气候变化的背景下&#xff0c;生态系统的季节性变化&#xff0c;尤其是植物的春季叶片展开和秋季叶片衰老&#xff08;EOS&#xff09;&#xff0c;对碳循环和区域气候调节起着至关重要的作用。然而&#xff0c;关于秋季叶…

腾讯云点播及声音上传

文章目录 1、开通腾讯云点播2、获取腾讯云API密钥3、完成声音上传3.1、引入依赖3.2、参考&#xff1a;接入点地域3.3、参考&#xff1a;任务流设置3.4、首先修改配置&#xff1a;3.4.1、 3.5、TrackInfoApiController --》 uploadTrack()3.6、VodServiceImpl --》 uploadTrack(…

计算存款利息-C语言

1.问题&#xff1a; 假设有本金1000元&#xff0c;想存一年&#xff0c;有三种方法可选择&#xff1a; A活期&#xff0c;年利率为0.0036&#xff1b; B一年期定期&#xff0c;年利率为0.0225&#xff1b; C存两次半年定期&#xff0c;年利率为0.0198。 请分别计算出一年后…

帮13岁小孩哥2分钟完成开发,这位AI程序员究竟是何方神圣?

通义灵码再升级&#xff0c;真AI程序员来了 随着通义系列基础模型能力的全面提升&#xff0c;各个具体领域的应用模型也随之飞升。这次在云栖大会上迎来重磅升级的&#xff0c;就包括用于代码生成的通义灵码。 一年前的通义灵码还只能完成基础的辅助编程任务&#xff0c;很难…

加快软件项目开发进度的6大技巧

加快软件项目的开发进度对于项目的成功与市场竞争力的提升至关重要。此举能够迅速响应市场变化&#xff0c;抢占市场先机&#xff0c;增强竞争力&#xff0c;同时降低开发成本&#xff0c;提升用户满意度。因此&#xff0c;加速开发是确保项目成功与市场竞争力的核心要素。若未…

捷途旅行者8月燃油SUV销量夺冠,遥遥领先!

2023年9月&#xff0c;捷途旅行者这款国内首款旅行越野SUV&#xff0c;如同一匹黑马般闯入国内汽车市场&#xff0c;凭借其方正硬朗的造型与13.99万元的亲民起售价&#xff0c;迅速点燃了消费者的购车热情。时隔一年&#xff0c;这款车的魅力依旧不减&#xff0c;2024年8月的销…

利用Leaflet.js集成强大的船舶管理页面:集成标记/路线/区域绘制和动态显隐功能

引言 在船舶管理领域&#xff0c;地理信息系统&#xff08;GIS&#xff09;技术的应用日益广泛。通过GIS技术&#xff0c;管理人员可以实时监控船舶的位置、航线以及与其他重要地理位置的关系。Leaflet.js作为一个轻量级但功能强大的前端地图框架&#xff0c;使得在Web页面上集…

如何用AI论文生成工具撰写一篇高质量的成人教育毕业论文

撰写一篇高质量的成人教育毕业论文并不简单&#xff0c;它有一定的步骤和策略。锐智AI今天就总结了一些关键的步骤&#xff0c;希望对即将毕业的你顺利完成论文写作&#xff1a; 介绍之前简单说下锐智AI&#xff0c;它是一款集论文大纲生成、内容填充、文献引用、查重修改于一…

Microsoft Edge WebView2运行时安装包获取

目前越来越多的软件将WebView2当做运行时&#xff0c;发现一些精简版的系统精简掉了WebView2或者人为误删除&#xff0c;一些软件无法正常运行&#xff0c;我们可以重新安装即可 浏览器访问WebView2官方页面 https://developer.microsoft.com/zh-cn/microsoft-edge/webview2/ …

头戴式耳机百元以内都有哪些推荐?头戴式耳机百元测评推荐

今天跟大家聊一聊头戴式耳机&#xff0c;无论是沉浸在游戏的世界中&#xff0c;还是专注于观看视频课程汲取知识&#xff0c;它都能为我们带来清晰、震撼的音质体验。对程序员来说&#xff0c;在嘈杂的工作环境中&#xff08;比如机房里&#xff09;&#xff0c;它的降噪功能显…

CVE-2024-44902 Thinkphp反序列化漏洞

Thinkphp v6.1.3至v8.0.4版本中存在反序列化漏洞&#xff0c;攻击者可利用此漏洞执行任意代码。 影响版本 v6.1.3 < thinkphp < v8.0.4 环境搭建 环境&#xff1a;php8.0.2thinkphp8.0.4memcached3.2.0 首先搭建 thinkphp 环境&#xff1a;thinkPHP 8.0.4 安装_thin…

02 BlockChain-- ETH

以太坊与比特币有什么不同&#xff1f; 以太坊立足比特币创新之上&#xff0c;于 2015 年启动&#xff0c;两者之间有一些显著不同。 从宏观的方面&#xff1a; 比特币就仅仅是比特币&#xff1b;以太坊&#xff08;Ethereum&#xff09;包括以太币&#xff08;Ether&#x…

Python可迭代对象(2)

目录 3。字典 字典的构造 字典的添加和修改 字典推导式的使用 以上全部代码编译结果展示 字典复习 4。集合(set) 集合的创建 集合的运算 集合的添加和删除元素 以上全部代码的编译结果 序列解包&#xff08;Sequence unpacking&#xff09; 3。字典 字典的构造 #字…

【第十六章:Sentosa_DSML社区版-机器学习之生存分析】

【第十六章&#xff1a;Sentosa_DSML社区版-机器学习之生存分析】 16.1 加速失效时间回归 1.算子介绍 加速失效时间回归模型Accelerated failure time (AFT)是一个监督型参数化的回归模型&#xff0c;它可以处理删失数据。它描述了一个生存时间的对数模型&#xff0c;所以它通…

Pygame中Sprite实现逃亡游戏1

在《Pygame中Sprite类实现多帧动画》系列中&#xff0c;通过pygame中的sprite类&#xff08;精灵类&#xff09;实现了多帧动画。在该动画的基础上&#xff0c;可以来实现一个逃亡游戏&#xff0c;如图1所示。 图1 逃亡游戏效果 从图1中可以看出&#xff0c;玩家被飞龙追赶&am…

【树莓派】python3程序获取CPU和GPU温度

前言代码以及展示总结 前言 来来来&#xff0c;先放参考文献 如何检查树莓派的温度⇨这个是通过两种指令获取温度&#xff0c;和我之前设置的状态栏显示有点大同小异。 读取树莓派4B处理器(CPU)的实时温度⇨这个也是指令 下面两个是代码了 树莓派实现温度监控并控制风扇散热 获…

powerBi -L4-分组求和

有如下的表格&#xff1a;我们想统计 不同商品的销售次数&#xff0c;根据商品ID进行分类&#xff0c;统计不同ID出现的次数 1.新建列&#xff1a; 2.输入如下的公式 分组统计序列 COUNTROWS(FILTER(数据源,[商品类别]EARLIER(数据源[商品类别])&&[索引]<EARLIE…

3.2 USART 通用同步/异步收发器

文章目录 什么是USARTUSART框图 stm32的Usart串口收发配置初始化发送接收 重定向的几种方法串口发送数据包 什么是USART USART&#xff08;Universal Synchronous/Asynchronous Receiver/Transmitter&#xff09;通用同步/异步收发器USART是STM32内部集成的硬件外设&#xff0…

李沐 模型选择、过拟合和欠拟合相关代码【动手学深度学习v2】

多项式回归 生成数据集 给定x,我们将使用以下三阶多项式来生成训练和测试数据的标签: y=5+1.2x−3.4+5.6+ϵ where ϵ∼( ). 噪声项ϵ服从均值为0且标准差为0.1的正态分布。 在优化

深入了解通用漏洞评分系统(CVSS)

1. 前言 在当今数字化的时代&#xff0c;网络安全问题日益凸显&#xff0c;漏洞的发现和评估成为保障系统安全的关键环节。而通用漏洞评分系统&#xff08;CVSS&#xff09;作为一种广泛应用的漏洞评估标准&#xff0c;对于准确衡量漏洞的严重程度起着至关重要的作用。本文将带…