当前位置:首页 » 《关注互联网》 » 正文

Cpp::STL—string类的使用与理解(下)(9)

20 人参与  2024年10月05日 18:01  分类 : 《关注互联网》  评论

点击全文阅读


文章目录

前言一、string类对象的修改operator+= (重点)assigninserterasereplacec_str 二、string类对象的查找findrfindsubstr 三、string类非成员函数operator+relational operatorgetline 四、VS和g++下string结构说明vs下string的结构g++下string结构 总结


前言

  我认为要想详尽认识string,请看该文档
  接上篇,我们继续来学习string这个类吧
  正文开始!


一、string类对象的修改

在这里插入图片描述

函数名称功能说明
operator+= (重点)在字符串后追加字符串或字符
append在字符串后拼接
push_back在字符串后尾插字符c
assign(奇葩)将空间中数据清空再添加所需内容
insert从某个位置开始插入字符
erase从某个位置开始删除len个字符
replace在字符串中某个区间位置的字符进行字符替换
pop_back尾删一个字符

operator+= (重点)

在这里插入图片描述
这个重载真的给了很大的自由度!,做到了让字符串可以加字符串、C字符串甚至是一个字符

在这里插入图片描述

所以,你会发现push_back()和append()没什么必要学习,至少我是真的懒得学这两个,如果真有需要,那看文档也是很方便的事

assign

功能:将空间中数据清空再添加所需内容,就是赋值的意思,如果出现空间不足问题,会自动扩容满足当前空间需求

int main(){string str1("hello world");str1.assign("xxx");cout << str1 << endl; // xxxreturn 0;}

记一下吧,虽然我目前还没遇到过具体实用场景

insert

功能:从字符串的某个位置开始插入

我们不妨来看下它的三个还算能用到的重载
string& insert (size_t pos, const string& str);
string& insert (size_t pos, const char* s);
iterator insert (iterator p, char c);

#include <iostream>#include <string>using namespace std;int main(){string s("C"); // C// insert(pos, str)在pos位置插入字符串strs.insert(1, "S"); // CS// insert(pos, string)在pos位置插入string对象string t("D");s.insert(2, t); // CSD// insert(pos, char)在pos位置插入字符chars.insert(s.end(), 'N'); // CSDNcout << s << endl; // CSDNreturn 0;}

erase

功能:从字符串的某个位置开始删除
在这里插入图片描述

#include <iostream>#include <string>using namespace std;int main(){string s("I like C++!!!");// erase(pos, n) 删除 pos 位置开始的 n 个字符s.erase(8, 5); // I like C// erase(pos) 删除 pos 位置的字符s.erase(s.end()-1); // I like// erase(pos1, pos2) 删除 [pos1pos2) 上所有字符s.erase(s.begin() + 1, s.end()); // Icout << s << endl; // Ireturn 0;}

replace

功能:在字符串中某个区间位置的字符进行字符替换
在这里插入图片描述

我们来注意这两个重载:
string& replace (size_t pos, size_t len, const char* s);
string& replace (size_t pos, size_t len, size_t n, char c);

#include <iostream>#include <string>using namespace std;int main(){string s("hello world");// replace(pos, len, str)将pos位置开始的len个字符替换为字符串strs.replace(6, 4, "CSDN"); // hello CSDNd// replace(pos, len, n, char)将pos位置开始的len个字符替换为n个字符chars.replace(10, 1, 3, '!'); // hello CSDN!!!cout << s << endl;return 0;}

对于insert、erase、replace来说,底层逻辑是挪动数据,时间复杂度很高,效率很低,能不使用就不使用,建议多使用operator+=

c_str

功能:返回C格式字符串(包括’\0‘)
在这里插入图片描述

#include <iostream>#include <string>using namespace std;int main(){string s("hello world ");const char* str = s.c_str();cout << str << endl; // hello world return 0;}

二、string类对象的查找

find

功能:如果找到相对应的字符或字符串后,find会返回该字符或字符串首位所在的索引位置(从0开始的下标索引位置),如果没有匹配成功,find则会返回npos(-1)
在这里插入图片描述

同样,我们观察这三个重载即可:
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(char c,size_t pos = 0) const

#include <iostream>#include <string>using namespace std;int main(){string s1("http://www.cplusplus.com/reference/string/string/find/");// find(string)正向搜索与string对象所匹配的第一个位置string s2("www");size_t pos1 = s1.find(s2);cout << pos1 << endl; // 7// find(str)正向搜索与字符串str所匹配的第一个位置char str[] = "cplusplus.com";size_t pos2 = s1.find(str);cout << pos2 << endl;  // 11// find(char)正向搜索与字符char所匹配的第一个位置size_t pos3 = s1.find(':');cout << pos3 << endl; // 4return 0;}

rfind

功能:如果找到相对应的字符或字符串后,rfind会返回该字符或者返回该字符串最后一个字符所在的索引位置;如果没有匹配成功,rfind则会返回npos(-1)
在这里插入图片描述

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 (char c, size_t pos = npos) const;

#include <iostream>#include <string>using namespace std;int main(){string s1("http://www.cplusplus.com/reference/string/string/find/");// rfind(string)反向搜索与string对象所匹配的第一个位置string s2("string");size_t pos1 = s1.rfind(s2);cout << pos1 << endl; //42// rfind(str)反向搜索与字符串str所匹配的第一个位置char str[] = "reference";size_t pos2 = s1.rfind(str);cout << pos2 << endl;  //25// rfind(char)反向搜索与字符char所匹配的第一个位置size_t pos3 = s1.rfind('/');cout << pos3 << endl; //53return 0;}

substr

功能:在str中pos位置开始,截取n个字符,然后将其返回
在这里插入图片描述

#include <iostream>#include <string>using namespace std;int main(){string s1("abcdef");string s2;// substr(pos, n)提取pos位置开始的n个字符序列作为返回值s2 = s1.substr(2, 4);cout << s2 << endl; // cdefreturn 0;}

三、string类非成员函数

  接下来介绍以下函数不属于string类中函数,而是属于全局函数。如果需要使用需要使用对应的头文件
在这里插入图片描述

operator+

在这里插入图片描述
  一样冗余的令人忍俊不禁,const char* s 能被隐式类型转换为 const string s,但一想可能早期CPU性能不行,于是很多情况下我们还是写了两种可能,这确实有一定的积极意义,其实可以想象当时编写string类的人的矛盾与纠结,但最后还是把不同的情况都给了出来,这可以看出来C++追求运行效率性能的决心

relational operator

在这里插入图片描述
  比较大小,注意我们比较的是字典序

getline

字符串里面最后一个单词的长度
我们不妨先来看这一道编程题
在这里插入图片描述
你可能感觉很简单,流插入一下str,并且反向查找空格字符

但是你会发现这样通过不了,如果你用的是cin >> str的话,原因在于读取字符串遇到空格或者换行符会终止问题,于是这里getline函数将从is中提取到的字符存储到str中,直到读取到换行符’\n’为止

另一种重载可以支持我们自行设定分隔符
istream& getline (istream& is, string& str, char delim);

#include <iostream>#include <string>using namespace std;int main(){string s;getline(cin, s, 'D'); // 输入:hello CSDNcout << s << endl; // 输出:hello CSreturn 0;}

四、VS和g++下string结构说明

注意:下述结构是在32位平台下进行验证,32位平台下指针占4个字节,有些内容暂时看不懂没关系,后期有个更全面的掌握再回头看也不迟,只是你要有个不同平台下string类的实现有很大的不同这个认识即可

vs下string的结构

  string总共占28个字节,内部结构稍微复杂一点,先是有一个联合体,联合体用来定义string中字符串的存储空间:

当字符串长度小于16时,使用内部固定的字符数组来存放当字符串长度大于等于16时,从堆上开辟空间
union _Bxty{ // storage for small buffer or pointer to larger onevalue_type _Buf[_BUF_SIZE];pointer _Ptr;char _Alias[_BUF_SIZE]; // to permit aliasing} _Bx;

  这种设计也是有一定道理的,大多数情况下字符串的长度都小于16,那string对象创建好之后,内部已经有了16个字符数组的固定空间,不需要通过堆创建,效率高。
  其次还有一个size_t字段保存字符串长度,一个size_t字段保存从堆上开辟空间总的容量,还有一个指针做一些其他事情

故总共占16+4+4+4=28个字节

在这里插入图片描述

g++下string结构

  G++下,string是通过写时拷贝实现的,string对象总共占4个字节,内部只包含了一个指针,该指针将来指向一块堆空间

struct _Rep_base{    size_type _M_length;    size_type _M_capacity;    _Atomic_word _M_refcount;};

总结

  使用 std::string 可以显著提高代码的安全性、可读性和可维护性,同时减少了手动内存管理带来的复杂性和风险。在现代 C++ 编程中,std::string 已成为处理字符串的首选工具,除非在特定情况下(如需要与 C 代码库兼容)才会选择使用 C-string
  马上就要来学习string类的底层实现了,期待吧!


点击全文阅读


本文链接:http://zhangshiyu.com/post/168158.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1