C++——string

目录

STL

STL六大组件

标准库中的string类

string类

string类常用接口 

构造函数

下标遍历[]

 迭代器

范围for

push_back()

 append()

insert() 

operator+=

pop_back()

erase()

reserve

 resize

 clear

c_str()

substr()

 find()

 rfind()

 find_first_of

getline

string库中的函数

to_string

从字符串装换为其他类型

深浅拷贝

拷贝构造的另一种写法 

赋值运算符重载的另一种写法


在讲解string之前先来简单了解一下STL

STL

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

STL六大组件


标准库中的string类

        为什么说他是标准库中的类呢,因为string比STL出现的还要早;就单单一个string类就有很多的函数接口,那这么多东西都要记住还是很困难的,但是不用担心,我们要记住的是其中常用的一些函数接口,不常用的记不住就去查文档https://cplusplus.com/reference/,个人认为这个文档还是非常好用的。

string类

  1. string是表示动态增长的char类型字符数组的字符串类。
  2. 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
  3. string在底层实际是:basic_string模板类的别名,typedef basic_string<char, char_traits, allocator>string; 
  4. 不能操作多字节或者变长字符的序列。
  5. 使用string类时,必须包含#include头文件以及using namespace std;
#include <string>
using namespace std;
string str = "abcdefg";

        在这个basic_string类下还有如图这样的,string使用的是typedef basic_string<char> string; 其他的就不是用char来实例化模板类,比如wstring使用wchar_t,就是宽字符,这样设计自然有它的道理在有些编码的地方需要使用它,主要使用的还是string。

string类常用接口 

构造函数

string ();	
string (const string& str);
string (const char* s);string s1; // 空字符串
string s2 = "abcdefg"; // 构造+拷贝构造->编译器优化为直接构造,这最后当然也包括\0
cout << s1 << endl; // 这里重载了流插入和流提取
string s3(s2); // 拷贝构造,这里肯定要用深拷贝实现string (const string& str, size_t pos, size_t len = npos); // 从sting对象的pos位置截取len长度的字符串
string s4(s2, 1, 2); // 从s2中下标为1的位置开始复制2个字符,上面是这个函数的声明
// 可以看到len有一个缺省参数是npos,len的长度为要几个字符,如果大于剩余的字符就拷贝到结尾
// 如果不传入参数就是npos
// npos是一个静态成员变量,static const size_t npos = -1
// 这是一个无符号的值,所以是一个很大的值,意思就是取到结尾,npos后面用的还是很多的s1 = s2; // 赋值重载

下标遍历[]

// string也支持下标访问
string s1("hello world");
cout << s1[0] << endl;
char& operator[](size_t pos); // 也有const版本,const对象会去匹配
// 引用返回可以减少拷贝,也可以修改返回值size_t size() const; // 返回字符的个数
for (int i = 0; i < s1.size(); i++) // 遍历每一个字符
{}

 迭代器

// 另一种遍历方式,迭代器,现在先理解为一个指针就可以了
string s1("hello");
string::iterator it = s1.begin();
// 在string类下的迭代器,所以其他容器里也有迭代器
// it是一个名字。通常都是it,简单理解就是指针
// iterator begin(); 返回对象的初始位置的指针
// iterator end(); 返回对象的最后一个位置的下一个,所以begin和end的区间是左闭右开
while (it != s1.end()) // 意思就是迭代器一直向后走,直到遇到最后一个位置的下一个
{// *it 解引用拿到这个对象it++;
}// 还有一种就是反向迭代器
string s2("hello");
string::reverse_iterator rit = s2.rbegin(); // rbegin()返回最后一个位置
while (rit != s2.rend()) // rend()返回第一个位置的前一个
{//...rit++;
}// 常量迭代器
string s3("hello");
string::const_iterator cit = s3.cbegin();
while (cit != s3.cend()) 
{//...cit++;
}// 反向常量迭代器
string s4("hello");
string::const_reverse_iterator crit = s4.crbegin();
while (crit != s4.crend())
{//...crit++;
}
        相比于迭代器,string使用下标遍历更好;但是迭代器还是很重要,毕竟有的容器只能用迭代器,它是所有容器通用的访问方式。如果这个声明太长了,也可以使用auto it。如果使用const迭代器的话还是会有const对象和普通对象的权限问题,注意一下就可以。

范围for

string s("hello");
// 范围for -- 自动迭代,自动判断结束
// 依次取s中每个字符,赋值给c
// 它只可以正向遍历
for (auto c : s)
{}// 范围for的底层其实就是迭代器,其实去查一下这两种写法的汇编就知道,基本是一样的
// 还有一个点就是范围for这里是赋值给c的,要是想修改就不行了
// c只是一份拷贝,它的值修改不会影响原来的值
// 所以这里也可以使用引用&
for (auto& c: s)
{}

push_back()

// 在字符串后添加一个字符
void push_back (char c);string s("hello");
s.push_back(' ');

 append()

// 在字符串后追加一个字符串
string& append (const string& str);
string& append (const char* s);
string& append (const char* s, size_t n); // 追加指定的s字符串的前n个字符
string& append (size_t n, char c); // 追加n个字符cstring s("hello");
s.append("_world")

insert() 

 string& insert (size_t pos, const string& str);string& insert (size_t pos, const char* s);	string s("hello");
s.insert(0, "x"); // 在下标为0的位置前插入"x"

operator+=

string& operator+= (const string& str);
string& operator+= (const char* s);
string& operator+= (char c);string s("hello");
s += '_'; // +=一个字符
s += s; // +=一个对象
s += "world"; // +=一个字符串

pop_back()

void pop_back();string s("hello");
s.pop_back(); // 删除字符串的最后一个字符

erase()

string& erase (size_t pos = 0, size_t len = npos); // 不指定删除个数就删到结尾string s("hello")
s.erase(0, 5) // 从下标为0的位置,删除5个字符

reserve

void reserve (size_t n = 0);string s;
s.reserve(1000); // 设置string对象的空间大小为1000字节,最后也不一定是1000字节,会对齐

 resize

void resize (size_t n);
void resize (size_t n, char c);string s;
s.resize(1000, 'x'); // 设置string对象的长度,可以开空间大小为1000字节并且初始化为'x'

 clear

void clear();string s;
s.resize(100, 's');
s.clear(); // 清空string对象

c_str()

const char* c_str() const; // 返回这个字符串的const char*形式string s("hello");
const char* ch = s.c_str();

substr()

string substr (size_t pos = 0, size_t len = npos) const;string s("hello world");
string s1 = s.substr(6, string::npos); // 从下标为6的位置开始截取字符串到结尾

 find()

size_t find (const string& str, size_t pos = 0) const;
size_t find (const char* s, size_t pos = 0) const;
size_t find (const char* s, size_t pos, size_t n) const;
size_t find (char c, size_t pos = 0) const;string s("hello_world");
size_t pos = s.find('_', 0); // 从下标为0的位置开始找字符'_',找到了返回这个字符的下标,找不到返回npos的值

 rfind()

size_t rfind (const string& str, size_t pos = npos) const;	
size_t rfind (const char* s, size_t pos = npos) const;
size_t rfind (const char* s, size_t pos, size_t n) const;
size_t rfind (char c, size_t pos = npos) const;string s("hello_world");
size_t pos = s.rfind('_'); // 从最后一个位置开始找,找不到返回npos

 find_first_of

size_t find_first_of (const string& str, size_t pos = 0) const;
size_t find_first_of (const char* s, size_t pos = 0) const;
size_t find_first_of (const char* s, size_t pos, size_t n) const;
size_t find_first_of (char c, size_t pos = 0) const;string str ("hello world");
size_t found = str.find_first_of("aeiou"); // 修改了文档的实例,匹配"aeiou"中的任意一个字符就可以
while (found!=std::string::npos)
{str[found]='*'; // 把这些字符替换成'*'found=str.find_first_of("aeiou",found+1);
}

getline

istream& getline (istream& is, string& str); // 相比较与cin,它可以输入带有空格符的字符串string s;
getline(cin, s);

string库中的函数

to_string

string to_string (int val); // 可以把int类型装换为string类型,不止是int、float、long等int n = 123456;
string s = to_string(n);

从字符串装换为其他类型

// 只举例了两种,还有很多种可以去看文档
string is = "1234";
string ds = "1234.00"
int n = stoi(is);
double d = stod(ds);

深浅拷贝

        在我们包含的string库中是不会出现这样的问题,别人都已经解决了,这个问题也不是很难。之前说的浅拷贝的问题是拷贝构造函数不写编译器会默认生成一个函数,按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,这样两个对象指向同一块空间,作用域结束后调用析构函数,这样同一块空间析构两次肯定会出问题,既然指向同一块空间出问题,那就再开一块空间分配个这个对象。

        赋值操作也会出问题,我们不写编译器会默认生成一个赋值运算符重载,这也是浅拷贝,会出现两个问题,第一个就是最后会析构两次,还有一个问题就是被赋值的对象原来所指向的空间丢失,这样会导致内存泄漏。

class string // 这里简单模拟实现一下string
{
public:string(const& string s) :_str(new char[s._capacity+1]) // 初始化列表,新开一块空间并且多开一个存放\0,_size(s._size),_capacity(s._capacity){strcpy(_str, s._str); // 再把s1的值拷贝过来}string& operator=(const satring& s) // 直接释放s1原来的空间,再申请一块和s3同样大小的空间就可以了{// 还要注意自己给自己赋值的情况,因为语法是支持这样做的// 如果不处理,开始就会直接释放自己的空间,这样也就没办法赋值了    if (this != &s){char* tmp = new char[s._capacity+1]; // +1位置存放\0, 先去开空间,保证空间开辟不出错,再去赋值和释放strcpy(tmp, s._str);delete[] _str; _str = tmp;_size = s._size;_capacity = s._capacity;}return *this; }
private:char* _str;size_t _size;size_t _capacity
};int main()
{string s1("hello");string s2(s1); // 用s1拷贝构造s2string s3("123456");s1 = s3; // 赋值操作也是有问题的,编译器生成的默认赋值,把s1指向s3指向的空间,但是原来s1指向的空间丢失,会造成内存泄露的问题return 0;
}

拷贝构造的另一种写法 

// string s2(s1)
string(const string& s):_str(nullptr),_size(0),_capacity(0)
{string tmp(s._str); // 这里调用了构造函数,开辟一块新的空间给tmp// 再把所有的成员变量交换,这样就把s1赋值给了s2,拷贝构造结束后,tmp会自动析构// 但是tmp交换完之后就是原来s2的值,s2原来没有开辟过,指向的空间是一块随机的// delete随机空间是会出错的,但是delete nullptr不会,所以在初始化列表中初始化一下swap(_str, tmp._str); swap(_size, tmp._size);swap(_capacity, tmp._capacity);
}

赋值运算符重载的另一种写法

// s1 = s2
string& operator=(const string& s)
{if (this != &s){string tmp(s);swap(_str, tmp._str);swap(_size, tmp._size);swap(_capacity, tmp._capacity);}return *this;
}// 还有一种
string& operator=(string s) // 这里的s是一个临时变量,是拷贝构造出来的,出了作用域也会自动释放
{swap(_str, s._str);swap(_size, s._size);swap(_capacity, s._capacity);return *this;
}

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

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

相关文章

MQ-小试牛刀

MQ MQ解决了什么问题&#xff1f; 异步处理 解耦合 削峰填谷 大规模数据处理 解耦 A系统发送数据到BCD三个系统&#xff0c;通过接口调用发送。如果 E 系统也要这个数据呢&#xff1f;那如果C系统现在不需要了呢&#xff1f;A系统负责人几乎崩溃… A系统跟其它各种乱七…

2023版 STM32实战9 RTC实时时钟/闹钟

RTC简介 实时时钟是一个独立的定时器。RTC模块拥有一组连续计数的计数器&#xff0c;在相应软件配置下&#xff0c;可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。 注意事项 -1- 要手动配置中断寄存器 -2- 需要等待写操作完成 -3- 时钟闹钟中段…

FPGA面试题(4)(跨时钟域处理)

跨时钟域处理方法 慢->快快->慢单bit在快时钟域同步打拍&#xff0c;将信号同步到快时钟域展宽后同步打拍多bit异步FIFO异步FIFO握手信号 一.打两拍 适用于单bit跨时钟域处理所谓的打两拍就是定义两级寄存器实现延时 那为什么是打两拍&#xff0c;不是打一拍&#x…

mysql面试题44:MySQL数据库cpu飙升的话,要怎么处理?

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:MySQL数据库cpu飙升的话,要怎么处理呢? 当MySQL数据库的CPU使用率飙升时,可能表示数据库负载过重或存在性能问题。以下是处理MySQL数据库CPU飙…

腾讯云优惠券种类、领取方法及使用教程分享

腾讯云是国内领先的云计算服务提供商&#xff0c;为用户提供丰富的云计算产品和服务。为了吸引更多用户使用腾讯云的产品和服务&#xff0c;腾讯云会定期推出各种优惠券活动。本文将为大家介绍腾讯云优惠券的种类、领取方法及使用教程。 一、腾讯云优惠券种类介绍 腾讯云优惠券…

项目管理的优秀软件推荐,助力提升团队效能!

我们知道&#xff0c;每个产品在上市的过程中都需要经历市场调研、研发设计、功能测试、上市评估、营销推广等阶段。作为项目经理&#xff0c;最关键的任务不仅是确保产品的顺利孵化和上市&#xff0c;还有管理团队。我们研究了许多项目管理用户&#xff0c;工作的难点是如何在…

{2023版}老牌配资平台排行报告:十大排名和实盘评估详情

随着投资者对股市的深入了解&#xff0c;越来越多的人开始选择配资交易。在配资平台的选择上&#xff0c;除了要注意平台的合法性和安全性外&#xff0c;平台的口碑和服务质量也是非常重要的考虑因素。为了方便投资者的选择&#xff0c;尚红网、倍悦网、兴盛网、诚利和、嘉正网…

文本情感计算技术(深度)

文本情感计算技术的发展得益于社交媒体的蓬勃发展。文本情感计算的研究至今已有 20年的历史&#xff0c;仍是国内外学术界和产业界的研究热点。随着新技术的变迁、新任务的出现&#xff0c;以及更高性能算法需求的增长&#xff0c;文本情感计算涉及多项有挑战性的研究任务。文本…

渗透测试KAILI系统的安装环境(第八课)

KAILI系统的安装环境(第八课) Kaili是一款基于PHP7的高性能微服务框架&#xff0c;其核心思想是面向服务的架构&#xff08;SOA&#xff09;&#xff0c;支持http、websocket、tcp等多种通信协议&#xff0c;同时还提供了RPC、Service Mesh、OAuth2等功能。Kaili框架非常适合构…

4大软件测试策略的特点和区别(单元测试、集成测试、确认测试和系统测试)

四大软件测试策略分别是单元测试、集成测试、确认测试和系统测试。 一、单元测试 单元测试也称为模块测试&#xff0c;它针对软件中的最小单元&#xff08;如函数、方法、类、模块等&#xff09;进行测试&#xff0c;以验证其是否符合预期的行为和结果。单元测试通常由开发人…

如何在.NET Core3.1 类库项目中使用System.Windows.Forms

网上说法大多都是直接添加对.Net Framework框架的引用&#xff0c;但是这种方法打包很不友好。于是开始了网络搜索&#xff0c;翻到了微软的文档&#xff0c;才找到直接引用 System.Windows.Froms 程序集的方法。还隐藏的很深&#xff0c;地址&#xff1a;Upgrade a Windows Fo…

查看和分析 IIS 日志文件以增强 Web 服务器安全性

Microsoft IIS服务器&#xff0c;无论是Web还是FTP&#xff0c;对于企业来说都是必不可少的。但是&#xff0c;IT 安全管理员的工作并不止于部署 IIS 服务器。部署后&#xff0c;管理员必须采取安全措施来保护这些服务器&#xff0c;监控 IIS 服务器安全性的一种行之有效的方法…

数据集笔记:分析OpenCellID 不同radio/ create_time update_time可视化

1 读取数据 &#xff08;以新加坡的cellID为例&#xff09; import geopandas as gpd import pandas as pdopencellidpd.read_csv(OpenCellID_SG.csv,headerNone,names[radio,mcc,net,area,cell,unit,lon,lat,range,samples,changeable1,created1,updated,AveSignal]) opence…

设计模式02———建造者模式 c#

首先我们打开一个项目 在这个初始界面我们需要做一些准备工作 建基础通用包 创建一个Plane 重置后 缩放100倍 加一个颜色 更换天空盒&#xff08;个人喜好&#xff09; 任务&#xff1a;使用【UI】点击生成6种车零件组装不同类型车 【建造者模式】 首先资源商店下载车模型 将C…

高效团队协作软件推荐:提升工作效率的优选方案!

使用团队协作软件有什么好处&#xff1f;可以摆脱过时的电子表格&#xff0c;有了单一的真实来源&#xff0c;您可以随时检查任何任务并获得可用的最新信息。 一目了然地查看所有正在进行的工作&#xff0c;看板式面板、甘特图和燃尽图等可视化工具可让您随时轻松获得项目的高级…

【web实现右侧弹窗】JS+CSS如何实现右侧缓慢弹窗动态效果『附完整源码下载』

文章目录 写在前面涉及知识点页面效果1、页面DOM创建1.1创建底层操作dom节点1.2 创建存放弹窗dom节点 2、页面联动功能实现&#xff08;关闭与弹出&#xff09;2.1 点击非右侧区域实现关闭2.2 点击叉叉及关闭按钮实现关闭功能 3、完整源码包下载3.1百度网盘3.2 123云盘3.3邮箱留…

HDMI 基于 4 层 PCB 的布线指南

HDMI 基于 4 层 PCB 的布线指南 简介 HDMI 规范文件里面规定其差分线阻抗要求控制在 100Ω 15%&#xff0c;其中 Rev.1.3a 里面规定相对放宽了一些&#xff0c;容忍阻抗失控在 100Ω 25%范围内&#xff0c;不要超过 250ps。 通常&#xff0c;在 PCB 设计时&#xff0c;注意控…

【深度学习实验】循环神经网络(一):循环神经网络(RNN)模型的实现与梯度裁剪

目录 一、实验介绍 二、实验环境 1. 配置虚拟环境 2. 库版本介绍 三、实验内容 0. 导入必要的工具包 1. 数据处理 2. rnn 测试 3. grad_clipping 4. 代码整合 经验是智慧之父&#xff0c;记忆是智慧之母。 ——谚语 一、实验介绍 本实验介绍了一个简单的循环神经网络…

排序算法——选择排序

一、介绍&#xff1a; 选择排序就是按照一定的顺序从选取第一个元素索引开始&#xff0c;将其储存在一个变量值中&#xff0c;根据排序规则比较后边每一个元素与这个元素的大小&#xff0c;根据排序规则需要&#xff0c;变量值的索引值进行替换&#xff0c;一轮遍历之后&#x…

通用监控视频web播放方案

业务场景 对接监控视频&#xff0c;实现海康大华等监控摄像头的实时画面在web端播放 方案一&#xff0c;使用 RTSP2webnode.jsffmpeg 说明&#xff1a;需要node环境&#xff0c;原理就是RTSP2web实时调用ffmpeg解码。使用单独html页面部署到服务器后&#xff0c;在项目中需要播…