【STL】string 类
创始人
2024-02-11 21:29:50

​🌠 作者:@阿亮joy.
🎆专栏:《吃透西嘎嘎》
🎇 座右铭:每个优秀的人都有一段沉默的时光,那段时光是付出了很多努力却得不到结果的日子,我们把它叫做扎根
在这里插入图片描述

目录

    • 👉为什么要学习 string 类👈
    • 👉标准库中的 string 类👈
    • 👉string 类的构造函数👈
      • **string()**
      • string(const char*)
      • string(size_t n, char c)
      • string(const string&s)
      • string (const char* s, size_t n)
      • string (const string& str, size_t pos, size_t len = npos)
    • 👉string 类的访问和遍历方式👈
      • **下标访问**
      • at
      • front 和 back
      • **范围for**
      • **迭代器**
    • 👉string 类对象的容量操作👈
      • size / length
      • capacity
      • max_size
      • clear
      • resize 和 reserve
      • shrink_to_fit()
    • 👉 string 类对象的修改操作👈
      • push_back
      • append
      • operator +=
      • insert
      • erase
      • assign
      • replace
      • find
      • c_str
    • 👉两道简单题👈
      • **[字符串最后一个单词的长度](https://www.nowcoder.com/practice/8c949ea5f36f422594b306a2300315da?tpId=37&&tqId=21224&rp=5&ru=/activity/oj&qru=/ta/huawei/question-ranking)**
      • **[验证回文串](https://leetcode.cn/problems/valid-palindrome/)**
    • 👉总结👈

👉为什么要学习 string 类👈

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

在 OJ 中,有关字符串的题目基本以 string 类的形式出现。如果还用 C语言先将轮子造出来,再去解题的话,代码量就会显得相当多,而且 string 类使用起来是相当的方便。

👉标准库中的 string 类👈

string 类有相当多的函数接口,我们无法将每个函数接口的功能都能记得清清楚楚。但对于一些非常常用的函数接口,我们要记住它们的函数原型、功能以及如何实现。

在学习的过程中,我们难免会记不清楚函数接口的原型、功能啊。这时候,我们就要学会查文档了。那么,我给大家推荐一个网站(https://legacy.cplusplus.com/) ,里面可以查到函数接口的相关信息。


在这里插入图片描述

什么是 string 类

  • string 类是表示字符串的字符串类。
  • string 类是 basic_string 模板类的一个实例,它使用 char 来实例化 basic_string 模板类,并用 char_traits 和 allocator 作为 basic_string 的默认参数。

在这里插入图片描述
在这里插入图片描述

为什么会将 string 设置成模板呢?因为这里涉及了编码问题。那什么是编码呢?编码是信息从一种形式或格式转换为另一种形式的过程(映射关系),也称为计算机编程语言的代码简称编码。用预先规定的方法将文字、数字或其它对象编成数码,或将信息、数据转换成规定的电脉冲信号。而大家第一次接触的编码可能就是 ASCII 码(美国信息交换标准代码)。

在这里插入图片描述

除了 ASCII 码,还有统一码,也称为万国码。

在这里插入图片描述
统一码中用的比较多的就是 UTF-8,因为 UTF-8 是兼容 ASCII 码的。关于统一码的编码规则和相关编码的优缺点,大家可以百度查询,我就不赘述了。

除了统一码外,还有 GBK 编码,这是中国国标的编码,其采用的是双字节编码方案。

在这里插入图片描述
那现在我给大家看一看 GBK 编码的演示。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
因为汉字博大精深,所以 GBK 编码就将同音字或音相近的字编在一起。注:一个汉字是占两个字的。

因为有了 UTF-8、UTF-16、UTF-32和GBK的不同编码形式,那么就有了 basic_string 模板类。大家可以根据自己的需求采用不同的类。而我们今天所学的 string 类是存储的是 char。

// 动态增长的字符数组
template
class basic_string
{
private:T* _str;size_t _size;size_t _capacity;
};
typedef basic_string string;

在这里插入图片描述

总结

  • string 是表示字符串的字符串类
  • 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作 string 的常规操作。
  • string 在底层实际是 basic_string 模板类的别名,typedef basic_string string;
  • 不能操作多字节或者变长字符的序列。
  • 在使用 string 类时,必须包含 #include 头文件以及using namespace std;

👉string 类的构造函数👈

string 类对象的常见构造
在这里插入图片描述

(constructor)函数名称功能说明
string() (重点)构造空的string类对象,即空字符串
string(const char* s)(重点)用字符串来构造string类对象
string(size_t n, char c)string类对象中包含n个字符c
string(const string&s) (重点)拷贝构造函数

string()

该构造函数是无参的构造函数,其构造出来的对象的size为 0,capacity的大小取决于编译器是如何实现 string类的。

在这里插入图片描述

string(const char*)

该构造函数是用常量字符串去构造一个对象出来,也是很常用的一个构造函数。
在这里插入图片描述
注:+= 是 string 类的运算符重载,可以在 string 类对象的末尾默认插入字符或者字符串,后面的内容会讲解其模拟实现。<< 也是 string 类的运算符重载。

在这里插入图片描述
除了上面的string s2("广东省深圳市")这样的写法,还可以想string s3 = "hello world"这样写。因为string(const char*)的函数原码没有用explicit修饰,可以支持隐式类型转换。先生成一个临时对象,再用临时对象去拷贝构造我们想要的对象s3,但是这个过程会被编译器优化成string s3("hello world")

string(size_t n, char c)

这个构造函数是用 n 个 字符来创建一个对象。

在这里插入图片描述

string(const string&s)

这个是 string 类的拷贝构造函数,也是相当的重要,一定要掌握。

在这里插入图片描述
注:因为 s6 之前是没有创建的,所以string s6 = s2调用的是拷贝构造函数。如果 s6 之前已经创建好了,那么s6 = s2调用的就是赋值运算符重载。

string (const char* s, size_t n)

这个构造函数是用字符串 s 的前 n 个字符来创建一个 string 类对象。注:n 最好不要超过字符串 s 的长度,否则创建出来的对象将未知。不过这个函数也不经常使用,要使用的话,就可以查一下文档。

在这里插入图片描述
在这里插入图片描述
注:string 类的 << 运算符重载并不是以'\0'作为打印的结束标志,而是打印到 string 类对象最后的一个字符。只是'\0'在 VS2022无法显示出来。所以,就出现了以上的打印结果。

string (const string& str, size_t pos, size_t len = npos)

该函数是用对象 str 从 pos 位置起的的 len 个字符来创建对象。注:npos 是 string 的静态const size_t成员变量,其值为 - 1,是非常大的一个正数。如果 len 很大,就会用 pos 位置到末尾位置之间的字符来创建对象。

在这里插入图片描述

在这里插入图片描述

👉string 类的访问和遍历方式👈

下标访问

在这里插入图片描述
注:size 是 string类的成员函数,size 是有效字符的个数,不包含'\0''\0'是标识字符。[ ]是运算符重载。

[ ]运算符重载原型

char& operator[](size_t pos)
{assert(pos < _size);return _str[i];
}

因为有断言,所以如果越界访问的话就要报错,所以用[ ]运算符重载时一定不能越界访问,就是越界读也不行。

在这里插入图片描述

at

在这里插入图片描述
at 函数也可以访问 string 类对象的数据,其参数为 pos。at 函数也会进行越界检查,如果发生了越界,就会抛出异常。
在这里插入图片描述

front 和 back

front 和 back 这个函数接口,就是返回头部和尾部的字符。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
需要注意的是:空的 string类对象不能调用这两个函数接口。

范围for

在这里插入图片描述
范围 for 的底层原理就是迭代器,那迭代器就是类似于指针的东西,也有可能不是指针。不过,迭代器用起来非常像指针。

下标遍历和范围 for 遍历各有各的优势,自己可以针对不同的场景使用。

在这里插入图片描述
注:swap是交换的模板函数,reverse是逆置算法的函数接口,其两个参数为迭代器。

在这里插入图片描述
在这里插入图片描述

迭代器

迭代器iterator的使用方式像指针,底层实现有可能是指针,也有可能不是指针。

注:iterator是一种类型。

在这里插入图片描述

在这里插入图片描述
可以看到迭代器用起来就像是指针一样。注:s1.begin()是返回s1第一个元素位置的迭代器,s1.end()是返回最后一个元素的下一个位置的迭代器。

在这里插入图片描述

注:迭代器和范围 for 是各种容器通用的访问形式,而下标[ ]只适用于 string 和 vector。

比如:vector 的迭代器变量。

	vector v;vector::iterator vit = v.begin();while (vit != v.end()){cout << *vit << ' ';vit++;}cout << endl;

这些迭代器使用起来都是非常像的,只是换了个容器而已。除了正向迭代器,还有反向迭代器reverse_iterator。现在,我们也来学习一下。

在这里插入图片描述
在这里插入图片描述
rbegin获取最后一个数据位置的reverse_iterator,rend获取第一个数据前一个位置的reverse_iterator。注:如果类型名过长的话,可以使用auto关键字自动推导类型。

如果我们想要用迭代器来遍历用 const 关键字修饰的类对象,那么就要使用正向迭代器const_iterator或者方向迭代器const_reverse_iterator。那么,我就给大家演示一下反向迭代器的使用。

在这里插入图片描述
注:权限只能缩小和平移,不能够放大,否则无法通过编译。如果在迭代器的最前面加上const关键字,那么迭代器就无妨自增或者自减。

在这里插入图片描述

四种迭代器总结

在这里插入图片描述
除了迭代器有const和非const的,[] 运算符重载也用const和非const的版本。这两个版本的函数形成函数重载。那什么样的函数什么时候要实现const版本的,什么时候要实现非const版本的。见下图:

在这里插入图片描述

👉string 类对象的容量操作👈

函数名称功能说明
size(重点)返回字符串有效字符长度
length返回字符串有效字符长度
capacity返回空间总大小
empty(重点)检测字符串释放为空串,是返回true,否则返回false
clear(重点)清空有效字符
reserce(重点)为字符串预留空间
resize(重点)将有效字符的个数该成n个,多出的空间用字符c填充

size / length

size 和 length 都是返回字符串的有效字符长度,功能一样的。只有 string 类有 length 的函数,而其它容器只有 size 的函数接口。

在这里插入图片描述

capacity

capacity 是返回 string 类对象的容量大小的函数接口。

在这里插入图片描述

max_size

max_size 函数接口返回的是 string 类对象能存储有效字符的最多个数,该大小取决于编译器的实现。注:这个函数接口没什么用。

在这里插入图片描述

clear

clear 是清空类对象的数据,但一般不会清空类对象的空间。

在这里插入图片描述

resize 和 reserve

resize 是修改 string 类的有效字符的个数 size 的,而reserve 是修改 string 类对象的容量。这两个函数接口时非常重要的,因为这往往涉及了扩容和缩容的问题。那我们现在通过下面的代码了解一下 string 类的扩容机制。

VS2022 下 string 类的扩容机制

void TestPushBack()
{string s;size_t sz = s.capacity();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';}}
}

在这里插入图片描述
Linux 下 string 类的扩容机制
在这里插入图片描述
通过上面的图片,我们就可以发现 VS2022 string类的扩容倍数大约是1.5倍,而 Linux 下 string 类的扩容倍数时2倍。所以,string 类的扩容倍数取决于编译器的实现,对于 STL 中的其它容器的扩容机制也一样。

其实扩容是有效率上的消耗的。如果我们知道需要多少的空间来存储数据,那么我们就可以借助 reserve 来提前讲空间开好,这样就可以避免频繁的扩容。

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
我们用 reserve 函数先将 s 的容量开到了 100,避免频繁的扩容,提高效率。

注意,reserve 函数不会对 size 进行修改。如果想要修改 size,就要通过 resize 函数接口了。

在这里插入图片描述
在这里插入图片描述
注:当 size 的第一个参数缺省且 n > capacity时,会插入'\0'。当 n 小于 capacity 时,一般不会缩容。

总结
resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。

reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于 string的底层空间总大小时,reserver不会改变容量大小。

shrink_to_fit()

在这里插入图片描述
shrink_to_fit 函数接口的功能是使 capacity 和 size 保持一致。
在这里插入图片描述
注:上面的程序 capacity 好像没有和 size保持一致,这是跟 VS的对齐规则有关系

👉 string 类对象的修改操作👈

函数名称功能说明
push_back在字符串后尾插字符c
append在字符串后追加一个字符串
operator+= (重点)在字符串后追加字符串str
c_str(重点)返回C格式字符串
find + npos(重点)从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置
rfind从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置
substr在str中从pos位置开始,截取n个字符,然后将其返回

push_back

在这里插入图片描述

append

在这里插入图片描述
append 重载了很多函数,不过我们只需要掌握一些常用的函数接口就行了。其他要用的话,可以再查看文档。

在这里插入图片描述

operator +=

append 函数接口不是最常用的,operator += 运算符重载才是最经常用的函数接口,可读性高,使用方便。

在这里插入图片描述

在这里插入图片描述

insert

在这里插入图片描述
在这里插入图片描述
注:insert 的接口不经常用,其时间复杂度为 O(N),其接口也比较简单,在这里就不赘述了。

erase

在这里插入图片描述

在这里插入图片描述
注:string& erase (size_t pos = 0, size_t len = npos)该函数是从 pos 位置删除 len 个字符,如果pos大于size,将会抛出异常;如果pos+len>=size,将会删除pos删除pos位置之后的所有字符以及pos位置上的字符。iterator erase (iterator p)的参数是迭代器,返回值是迭代器。该迭代器指向现在占据第一个被擦除字符位置的字符,如果不存在这样的字符,则返回string::end。iterator erase (iterator first, iterator last)该函数删除[first, last)之间的字符,返回值同上。

assign

在这里插入图片描述
在这里插入图片描述
assign 这个函数相当于赋值。

replace

在这里插入图片描述
在这里插入图片描述
这个接口了解即可,因为其效率不是很高。

find

在这里插入图片描述

在这里插入图片描述
find 函数是一个查找的函数接口,是比较重要的函数接口,需要熟练掌握。

在这里插入图片描述
replace 函数接口的时间复杂度是比较高的,所以上面的代码可以修改成下面的代码。

在这里插入图片描述
要求取出文件名的后缀

在这里插入图片描述
substr的函数原型

在这里插入图片描述
Linux 下的文件可能会有很多后缀,那如果我们想取出最后一个后缀,怎么解决呢?这时候,就要借助 rfind 函数了。

在这里插入图片描述
在这里插入图片描述

find_first_of

在这里插入图片描述
该函数可以查找给定字符串中的任意一个字符。在这里,就给大家看一个列子,帮助大家理解这个函数。

在这里插入图片描述

c_str

c_str 函数接口返回的是 string 类对象的数组首元素的地址。

打印文件里的内容

#include 
using namespace std;
#include 
#include 
void stringTest14()
{string file("Test.cpp");FILE* fout = fopen(file.c_str(), "r");assert(fout);char ch = fgetc(fout);while (ch != EOF){cout << ch;ch = fgetc(fout);}
}int main()
{stringTest14();return 0;
}

在这里插入图片描述

👉两道简单题👈

字符串最后一个单词的长度

在这里插入图片描述

#include 
using namespace std;
#include int main() 
{string s;getline(cin, s);size_t pos = s.rfind(' ');cout << s.size() - pos - 1 << endl;return 0;  
}

在这里插入图片描述
注:cin 遇到空格或者换行就不会在输入缓冲区里提取数据。

getline

在这里插入图片描述
注:getline 函数也可以从输入缓冲区提取数据,其提取结束标识可以自己指定。如果不指定,默认为换行符。

验证回文串

如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样。则可以认为该短语是一个回文串 。

字母和数字都属于字母数字字符。

给你一个字符串 s,如果它是回文串 ,返回 true ;否则,返回 false 。

思路:先写一个函数判断是不是数字或者字母,如果利用快排的思想,定义两个下标 begin 和 end,略过其他字符,找出字母或者数字,比较是否相等。如果不相等,直接返回 false;如果相等,则 begin++,end–。如果循环结束,还是相等,则该字符串是题目所描述的回文串,返回true。

class Solution 
{
public:bool isLetterOrNumber(char ch){return (ch >= '0' && ch <= '9')|| (ch >= 'a' && ch <= 'z')|| (ch >= 'A' && ch <= 'Z');}bool isPalindrome(string s) {// 先将大写字母转换成小写字母,再进行判断for(auto& ch : s){if(ch >= 'A' && ch <= 'Z')ch += 32;            }int begin = 0, end = s.size() - 1;while(begin < end){while(begin < end && !isLetterOrNumber(s[begin]))++begin;while(begin < end && !isLetterOrNumber(s[end]))--end;if(s[begin] != s[end]){return false;}else{++begin;--end;}}return true;}
};

在这里插入图片描述

👉总结👈

本篇博客主要讲了为什么要学习 string 类,编码问题,以及 string 类常用的函数接口。对于常用的函数接口,希望大家能够熟练掌握;不常用的函数接口,有个印象就可以了,不会的时候可以查文档。那么以上就是本篇博客的全部内容了,如果大家觉得有收获的话,可以点个三连支持一下!谢谢大家!💖💝❣️

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...