【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.hqwc.cn/news/661882.html

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

相关文章

低空经济+无人机:细分赛道万亿级别市场崛起,可能成为年内最大热点

近年来&#xff0c;低空经济作为一种新兴的产业&#xff0c;正在快速发展。特别是在无人机的快速普及下&#xff0c;低空经济已经展现出巨大的潜力和市场前景。无人机从狭窄的“会飞的相机”逐渐进入到更多场景&#xff0c;从消费市场进入到工业市场&#xff0c;不断拓展其应用…

AJAX家政系统 自营+多商家(高级授权)+独立端口 -源码下载

应用介绍 后台&#xff1a;https://service.hnajax.com/hxeJVakAdf.php/index/login AJAX家政系统 自营多商家(高级授权)独立端口 基于FastAdmin和原生微信小程序开发的一款同城预约、上门服务、到店核销家政系统&#xff0c;用户端、服务端(高级授权)、门店端(高级授权)各端…

如何使用Go语言进行并发安全的数据访问?

文章目录 并发安全问题的原因解决方案1. 使用互斥锁&#xff08;Mutex&#xff09;示例代码&#xff1a; 2. 使用原子操作&#xff08;Atomic Operations&#xff09;示例代码&#xff1a; 3. 使用通道&#xff08;Channels&#xff09; 在Go语言中&#xff0c;进行并发编程是常…

综合性练习(后端代码练习3)——留言板

目录 一、准备工作 二、约定前后端交互接口 1、需求分析 2、接口定义 &#xff08;1&#xff09;发布留言 &#xff08;2&#xff09;获取留言 三、实现服务器代码 1、lombok介绍 &#xff08;1&#xff09;引入依赖 &#xff08;2&#xff09;使用lombok &#xff…

OI Wiki—枚举

//新生训练&#xff0c;搬运整理 简介 枚举&#xff08;英语&#xff1a;Enumerate&#xff09;是基于已有知识来猜测答案的问题求解策略。 枚举的思想是不断地猜测&#xff0c;从可能的集合中一一尝试&#xff0c;然后再判断题目的条件是否成立。 要点 给出解空间 建立简洁…

mac虚拟机软件哪个好 mac虚拟机怎么安装Windows 苹果Mac电脑上受欢迎的主流虚拟机PK Parallels Desktop和VM

什么是苹果虚拟机&#xff1f; 苹果虚拟机是一种软件工具&#xff0c;它允许在非苹果硬件上运行苹果操作系统&#xff08;如ios&#xff09;。通过使用虚拟机&#xff0c;您可以在Windows PC或Linux上体验和使用苹果的操作系统&#xff0c;而无需购买苹果硬件。 如何使用苹果虚…

字节大小转换字符串

#pragma once#include <string> #include <stdint.h>#ifdef _UNICODE using _tstring std::wstring; #else using _tstring std::string; #endif// // brief: 字节大小格式化 // param: nBytesSize 输入字节大小 // param: bSpace 输出是否需要…

2024年最新省市县三级行政区划数据(审图号:GS(2024)0650号)

2024年省、市、县三级行政区划数据由国家基础地理信息中心发布&#xff0c;通过《2024版国家地理信息公共服务平台&#xff08;天地图&#xff09;》正式对外提供。这份数据涵盖了最新的省市县三级行政区划信息&#xff0c;更新于2024年1月&#xff0c;提供了详细的矢量数据下载…

vscode 使用code runner 运行代码输出乱码

vscode 使用code runner 运行代码输出乱码 先指出问题所在&#xff1a; 代码文件使用的编码格式和终端使用的编码格式不一致&#xff0c;查看代码文件右下角&#xff0c;会显示代码文件的编码格式。 测试代码如下&#xff1a; #include<iostream> using namespace std…

Python爬虫-BeautifulSoup解析

1.简介 BeautifulSoup 是一个用于解析 HTML 和 XML 文档的 Python 库。它提供了一种灵活且方便的方式来导航、搜索和修改树结构或标记文档。这个库非常适合网页抓取和数据提取任务&#xff0c;因为它允许你以非常直观的方式查询和操作文档内容。 2.安装 Beautiful Soup 终端输…

Java学习第02天-类型转换、运算符

目录 类型转换 自动类型转换 表达式的自动类型转换 强制类型转换 运算符 基本运算符 案例解答 连接字符串 自增自减运算符 面试习题 赋值运算符 比较运算符 逻辑运算符 基本逻辑运算符 短路逻辑运算符 三元运算符 基础知识 拓展案例 运算符优先级 读取用户…

DICOM 测试工具

一个DICOM测试工具。 引用了 fo-dicom 。fo-dicom 算是比较好用的&#xff0c;我的另外一个项目也是用了它。 using System; using System.Collections.Generic; using System.Data; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; …