【C++程序员的自我修炼】string 库中常见的用法 (一)

唤起一天明月
照我满怀冰雪
浩荡百川流
鲸饮未吞海

剑气已横秋


目录

 string 库的简介

string 的一些小操作

构造函数的使用

拷贝构造的常规使用

指定拷贝内容的拷贝构造

拷贝字符串开始的前 n 个字符

用 n 个字符初始化 

计算字符串的长度

string 的三种遍历方式

常规的for循环

operator[]运算符重载

迭代器遍历

auto 自动类型推导

string 的追加字符或字符串

从 string 末尾插入一个字符

string 的追加一个字符串

 

契机 ✨ 

我们在 C语言 阶段中,字符串是以 \0 为结尾的一些字符的集合,为了操作方便,C标准库 中提供了一些 str 系列的库函数(比如说:strlenstrcpy), 但是这些库函数与字符串是分离开的,不太符合 OOP (面向对象)的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。

举个栗子~比如 strcpy C语言 中我们知道这个函数的作用是将一块空间拷贝到另一块空间

首先两个空间都需要自己提供,而且要保证目标的空间和拷贝空间是一样大的或者比它大的

以上的例子我们将 s1 拷贝到 s2 中,如果 s2 的空间小于 s1strcpy 是不会管的,这个时候就会发生越界访问,像这类我们既要管空间又要管方法的函数用起来是很麻烦的

为了方便、快捷的进行我们字符串的编程,在我们 C++ 中就提供了字符串类也就是 string

为了更好的学习 string ,我们最好要学会看 string 库的文档:string 文档


 string 库的简介

string 是表示字符串的字符串类                                                                                                   
该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作 string 的常规操作           

通过以上的文档信息我们可以知道: 

string 其实就是一个模板,而 basic_string 就是模板类的别名:

typedef basic_string<char, char_traits, allocator> string

这里还有个点需要注意:

string 不能操作多字节或者变长字符的序列                                                                                      

剩下的就是别忘记包头文件哦(#include<string>) ~ 还有域限定符


string 的一些小操作

构造函数的使用

我们知道 string 是一个类,那么我们以前在类中的常规操作在 string 中能直接用吗?

-- 比如说:拷贝构造

我们发现 string 的设计其实是有点冗余的,单单一个拷贝构造其形式竟有 7 中之多

先来看一下我们熟悉的那几种的拷贝构造的用法

拷贝构造的常规使用
#include<iostream>
#include<string>
using namespace std;void TestString()
{// 创建一个 string 类string s1;// 构造string s2("hello world");cout << s2 << endl;// 拷贝构造string s3(s2);cout << s3 << endl;// 赋值构造string s4;s4 = s2;cout << s4 << endl;// 隐式类型转化,将字符串类型传化成自定义类型string s5 = "hello world";cout << s5 << endl;
}int main()
{TestString();return 0;
}

因为 string 库中已将帮我们写好了,我们放心用即可~


指定拷贝内容的拷贝构造
string (const string& str, size_t pos, size_t len = npos);

我们先来分析以上代码, 参数提供了一个字符串和两个无符号整型,结合文档我们不难理解:

str 字符串的第 pos 位置开始拷贝,直到拷贝完 npos 个字符结束

如果 npos 超出了 str 后面的字符长度就拷贝到结尾,如果不写 npos 默认拷贝考结尾

我们来验证一下: 

void TestString()
{string s1("I Love You");string s2(s1, 2, 4);cout << s2 << endl;string s3(s1, 2, 15);cout << s3 << endl;string s4(s1, 2);cout << s4 << endl;
}

先分析:
s1 是我们从第二个位置开始拷贝的,拷贝长度为 4 个字节也就是 Love

s2 是我们从第二个位置开始拷贝的,但是拷贝的字符长度超出了 str 后面的长度,所以是拷贝剩下的所有字符,也就是 Love You

s3 是我们从第二个位置开始拷贝的,没有写 npos 参数,所以是拷贝剩下的所有字符,也就是 Love You

注意:这里传的 pos 位置是下标哦 ~

这里可能有老铁会问,为什么 npos 不传参就是拷贝剩下的全部呢?

我们这里先看一下文档:

因为不传参,编译器就会给系统默认的值,也就是 -1
static const size_t npos = -1;

注意:这里的 -1 并不是真正的 -1,为什么无符号整会有负数?因为 -1 存的是它的补码就是全 F 。整型的范围大概是 21亿 多,而 size_t 就是 42亿 多。可想而知 npos 的值有多大!

我们简化来看其实不传 npos 的本质和传超过 str 的长度的 npos 是一样的,但是会比较方便


拷贝字符串开始的前 n 个字符
string (const char* s, size_t n);

 这个比较简单我们直接测试一下吧

void TestString()
{string s1("I Love You", 6);cout << s1 << endl;
}


用 n 个字符初始化 
string (size_t n, char c);

  这个比较简单我们直接测试一下吧

void TestString()
{string s1(10, 'x');cout << s1 << endl;
}

 string 设计的有些许冗余,我们只要掌握常规的构造就行,其他的方法最好也要了解一下


计算字符串的长度

为了更好的学习这两个函数,我们先参考一下文档:

我们发现这两个函数的功能都是一样的,都是返回 \0 之前的字符串长度:

void TestString()
{string s1("Hello World");cout << s1.size() << endl;cout << s1.length() << endl;
}

那么有两个都可以用,那么最好用哪一个呢? -- 建议用 size(与 STL 库对应)

在这里穿插讲个题外的小故事,C++ 委员初次设计 string 的时候是朝着 STL 方向去做的,当时惠普工作室已经有了一套模板库 -- STL,C++ 委员会觉得很好就规定为标准了。

大家可以看到 string 的许多设计和 STL 是一样的,比如说 -- 迭代器

length 算是 string 的专属,对于 STL 库中计算长度就只有 size

为了与 STL 同步,我们最好在 string 也用 size 


string 的三种遍历方式

常规的for循环
void TestString()
{string s1("hello world");for (int i = 0; i < s1.size(); i++){cout << s1[i];}
}
operator[]运算符重载

这里我想问各位老铁一个问题为什么字符串能 [ ] 访问单个字符呢?

-- 因为 [ ] 符号重载了

其实本质是这样的

s1.operator[](i)

 这样就可以像数组一样访问

我们可以看看 operator[ ] 的底层逻辑

class string
{
public:char& operator[](size_t i){assert(i < _size);return _str[i];}
private:char* _str;size_t _size;size_t _capacity;
};

 这里的 & 除了减少拷贝外,还有修改返回对象的良效

我们来看:

void TestString()
{string s1("hello world");for (int i = 0; i < s1.size(); i++){s1[i]++;cout << s1[i];}
}

这样我们不仅能访问字符串的元素还能修改!!!

还有一点如果我们的数组发生了越界,string 是可以检查出来的

错误示范:

void TestString()
{string s1("hello world");s1[20];
}

string 会报错提示,如果是平时我们数组越界是检查不出来的访问的是其他空间的值

所以 string 有点香 ~


迭代器遍历

我们先来了解一下迭代器的基本原理(先来参考一下文档)

现阶段我们这样片面的理解为 :就是类似于两个指针,begin() 指向字符串的首字符,end()指向字符串的末字符 ~

注意:begin()、end() 并不是指针(只是用法类似),它们的主要内容我们在下篇 STL库 再来讲:

我们可以先看看它们的类型:(typeid().name()显示一个对象的类型

cout << typeid(it1).name() << endl;

 打印出来就是这一长串 “东西” ,别急以后会解释,接下来我们实现一下迭代器的遍历方法

void TestString()
{string s1("hello world");string::iterator it1 = s1.begin();while (it1 != s1.end()){cout << *it1;it1++;}cout << endl;
}

这样就写完了 ~ 感觉不如第一种写法简洁,但是以后的用处很大比如:可以遍历链表和树形等 

我们可以先来感受一下:

#include<iostream>
#include<list>
using namespace std;void Test()
{list<int> lt1;lt1.push_back(1);lt1.push_back(2);lt1.push_back(3);list<int>::iterator it = lt1.begin();while (it != lt1.end()){cout << *it << " ";it++;}
}int main()
{Test();return 0;
}

或者以后写快排的时候也可以写迭代器:

sort(a.begin(), a.end());

表示对整个数据元素进行排序

void TestString()
{string s1("hello world");string::iterator it1 = s1.begin() + 6;while (it1 != s1.end()){cout << *it1;it1++;}cout << endl;
}

 我们还可以通过改变迭代器的位置来达到我们想要的遍历效果

总结:

begin:任何容器返回第一个数据位置的iterator

end:任何容器返回最后数据的下一个位置的iterator

我们可以通过改变迭代器的始末位置来达到遍历需求

 


auto 自动类型推导
void TestString()
{string s1("hello world");for (auto i : s1){cout << i;}cout << endl;
}

最简单的遍历方式,不过也有局限性 -- 只能从头遍历到尾(注意:底层是迭代器哦 ~ )


 

string 的追加字符或字符串

从 string 末尾插入一个字符

void TestString()
{string s1("hello world");s1.push_back('!');cout << s1 << endl;
}

相当于我们在链表中学的尾插,不过只能插入一个字符哦 ~

string 的追加一个字符串

个人感觉 string 的这个设计也有些冗余,其实 push_back 传个 char*s 就够了(疯狂吐槽)

我们来看一下 append 的用法:

void TestString()
{string s1("hello ");string s2("world");cout << s1.append(s2) << endl;
}

 讲到这里我再来介绍一下 另一种方式 (运算符重载 += )

我们来看一下,这里追加 字符 或者 字符串 都是可以的

void TestString()
{string s1("hello ");s1 += "world";cout << s1 << endl;s1 += '!';cout << s1 << endl;
}


 先介绍到这里啦~

有不对的地方请指出💞

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

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

相关文章

利用大型语言模型提升数字产品创新:提示,微调,检索增强生成和代理的应用

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

「笔试刷题」:字母收集

一、题目 描述 有一个 &#x1d45b;∗&#x1d45a; 的矩形方阵&#xff0c;每个格子上面写了一个小写字母。 小红站在矩形的左上角&#xff0c;她每次可以向右或者向下走&#xff0c;走到某个格子上就可以收集这个格子的字母。 小红非常喜欢 "love" 这四个字母。…

FFmpeg开发笔记(二十三)使用OBS Studio开启RTMP直播推流

OBS是一个开源的直播录制软件&#xff0c;英文全称叫做Open Broadcaster Software&#xff0c;广泛用于视频录制、实时直播等领域。OBS不但开源&#xff0c;而且跨平台&#xff0c;兼容Windows、Mac OS、Linux等操作系统。 OBS的官网是https://obsproject.com/&#xff0c;录制…

【报错处理】ib_write_bw执行遇到Couldn‘t listen to port 18515原因与解决办法?

要点 要点&#xff1a; ib默认使用18515端口 相关命令&#xff1a; netstat -tuln | grep 18515 ib_write_bw --help |grep port# server ib_write_bw --ib-devmlx5_1 --port88990 # client ib_write_bw --ib-devmlx5_0 1.1.1.1 --port88990现象&#xff1a; 根因&#xff…

为什么公共事业机构会偏爱 TiDB :TiDB 数据库在某省妇幼健康管理系统的应用

本文介绍了某省妇幼健康管理系统的建设和数据库架构优化的过程。原有的数据库架构使用了 StarRocks 作为分析层&#xff0c;但随着业务的发展&#xff0c;这套架构暴露出诸多痛点&#xff0c;不再适应妇幼业务的需求。为解决这些问题&#xff0c;该系统选择了将原有架构中的 St…

OBSERVER(观察者)-- 对象行为模式

意图&#xff1a; 定义对象间地一种一对多地依赖关系&#xff0c;当一个对象地状态发生改变时&#xff0c;所有对于依赖于它的对象都得到通知并被自动更新。 别名&#xff1a; 依赖(Dependents), 发布-订阅(Publish-Subsribe) 动机&#xff1a; 将一个系统分割成一系列相互协…

使用Python及R语言绘制简易数据分析报告

Pytohn实现 在python中有很多包可以实现绘制数据分析报告的功能&#xff0c;推荐两个较为方便的包&#xff1a;pandas-profiling 和 sweetviz 。 使用 pandas-profiling 包&#xff08;功能全面&#xff09; 这个包的个别依赖包与机器学习的 sklearn 包的依赖包存在版本冲突&a…

【C++中的模板】

和你有关&#xff0c;观后无感................................................................................................................. 目录 前言 一、【模板的引入和介绍】 1、泛型编程 2、【模板的介绍】 二、【 函数模板】 2.1【模函数板的介绍】 1.…

修改word文件的创作者方法有哪些?如何修改文档的作者 这两个方法你一定要知道

在数字化时代&#xff0c;文件创作者的信息往往嵌入在文件的元数据中&#xff0c;这些元数据包括创作者的姓名、创建日期以及其他相关信息。然而&#xff0c;有时候我们可能需要修改这些创作者信息&#xff0c;出于隐私保护、版权调整或者其他实际需求。那么&#xff0c;有没有…

【开源设计】京东慢SQL组件:sql-analysis

京东慢SQL组件&#xff1a;sql-analysis 一、背景二、源码简析三、总结 地址&#xff1a;https://github.com/jd-opensource/sql-analysis 一、背景 开发中&#xff0c;无疑会遇到慢SQL问题&#xff0c;而常见的处理思路都是等上线&#xff0c;然后由监控报警之后再去定位对应…

vue 前端读取Excel文件并解析

前端读取Excel文件并解析 前端如何解释Excel呢 平时项目中对于Excel的导入解析是很常见的功能&#xff0c;一般都是放在后端执行&#xff1b;但是也有特殊的情况&#xff0c;偶尔也有要求说前端执行解析&#xff0c;判空&#xff0c;校验等&#xff0c;最后组装成后端接口想要的…

【大数据】利用 Apache Ranger 管理 Amazon EMR 中的数据权限

利用 Apache Ranger 管理 Amazon EMR 中的数据权限 1.需求背景简介2.系统方案架构图3.主要服务和组件简介3.1 Amazon EMR3.2 Simple Active Directory3.3 Apache Ranger 4.部署步骤4.1 部署 Simple AD 服务4.2 部署 Apache Ranger4.3 部署 Amazon EMR4.4 在 Amazon EMR 的主节点…

【数据结构】二叉树(带图详解)

文章目录 1.树的概念1.2 树的结构孩子表示法孩子兄弟表示法 1.3 相关概念 2.二叉树的概念及结构2.1 二叉树的概念2.2 数据结构中的二叉树-五种形态2.3 特殊的二叉树2.4 二叉树的存储结构顺序存储链式存储 2.5 二叉树的性质 3. 堆3.1 堆的定义3.2 堆的实现堆的结构堆的插入向上调…

java技术栈快速复习02_前端基础知识总结

前端基础 经典三件套&#xff1a; html&#xff08;盒子&#xff09;css&#xff08;样式&#xff09;JavaScript&#xff08;js&#xff1a;让盒子动起来&#xff09; html & css HTML全称&#xff1a;Hyper Text Markup Language(超文本标记语言)&#xff0c;不是编程语…

不科学上网使用Hugging Face的Transformers库

参考 Program Synthesis with CodeGen — ROCm Blogs (amd.com) HF-Mirror - Huggingface 镜像站 https://huggingface.co/docs/transformers/v4.40.1/zh/installation#%E7%A6%BB%E7%BA%BF%E6%A8%A1%E5%BC%8F 准备 apt show rocm-libs -a pip install transformers python …

计算机网络—数据链路层

一、数据链路层的基本概念 结点&#xff1a;主机、路由器 链路&#xff1a;网络中两个结点之间的物理通道&#xff0c;链路的传输介质主要有双绞线、光纤和微波。分为有线链路、无线链路 数据链路&#xff1a;网络中两个结点之间的逻辑通道&#xff0c;把实现控制数据协议的…

ABAP 查找第二代增强

文章目录 ABAP 查找第二代增强第一种方法-根据包去查找第二种方法-通过MODX_FUNCTION_ACTIVE_CHECK重要的表MODSAP表TFDIR表TFTIT表 ABAP 查找第二代增强 第一种方法-根据包去查找 第二种方法-通过MODX_FUNCTION_ACTIVE_CHECK 第二代增强&#xff08;基于函数模块的增强&…

git如何将多个commit合并成一个?

我们使用git进行版本控制&#xff0c;在本地开发完某个功能时&#xff0c;需要提交commit&#xff0c;然后push至开发分支。简单的功能还好&#xff0c;几个commit可能就好了。但是如果功能比较复杂&#xff0c;commit多达十几甚至几十个时&#xff0c;commit管理就会很冗长。比…

【IC设计】CRC(循环冗余校验)

目录 理论解读CRC应用CRC算法参数解读常见CRC参数模型 设计实战校招编程题分类串行输入、并行计算、串行输出**串行计算、串行输出&#xff08;线性移位寄存器&#xff09;LSFR线性移位寄存器&#xff08;并转串&#xff09;(并行计算)模二除 总结——串行、并行计算的本质参考…

成功解决STM32-No ST-LINK detected问题!

本文目录 一、原因二、解决方法一&#xff1a;有复位按键方法二&#xff1a;没有复位按键 一、原因 在之前一直都用的好好的&#xff0c;突然出现这个问题&#xff0c;原因只有两个&#xff1a; 接线松了&#xff0c;或者杜邦线损坏&#xff0c;换新的线试一下。上一次下载到…