当前位置: 首页 > news >正文

【C++】string类 - 库中的常见使用

作者主页:lightqjx

本文专栏:C++

目录

前言(简单了解STL)

一、为什么要学习string类

二、 string类的简介

三、string的库中常见使用

1. 常见构造函数

2. 对容量的操作

3. 访问及遍历操作

(1)常见操作

(2)string的迭代器

4. string类对象的增加操作

5. 对string对象进行查找

6. string类非成员函数

四、总结


前言(简单了解STL)

概念 

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

发展

        STL最初是惠普实验室完成的,这是原始版本(HP版本),HP版本是所有STL实现版本的始祖;后来继承自HP版本,又出现了P. J. 版本、RW版本、SGI版本。

        其中的需要注意的是SGI版本:需要由Silicon Graphics Computer Systems,Inc公司开发,继承自HP版 本。被GCC(Linux)采用,可移植性好,可公开、修改甚至贩卖,从命名风格和编程 风格上看,阅读性非常高。所以后面文章学习STL要阅读的部分源代码,主要参考的就是这个版本。

STL的六大组件

参照下图:

所以接下来关于string的学习,其实就是对容器的第一步学习,也是对STL的第一步学习。

缺陷(简单了解)

  1. STL库的更新太慢了。这个得严重吐槽,上一版靠谱是C++98,中间的C++03基本一些修订。C++11出来已经相隔了13年,STL才进一步更新。
  2. STL现在都没有支持线程安全。并发环境下需要我们自己加锁。且锁的粒度是比较大的。
  3. STL极度的追求效率,导致内部比较复杂。比如类型萃取,迭代器萃取。
  4. STL的使用会有代码膨胀的问题,比如使用vector/vector/vector这样会生成多份代码,当然这是模板语法本身导致的。

接下来,开始进入正题:认识string类并学习string类的常见使用。


一、为什么要学习string类

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

        在OJ题型中,有关字符串的题目基本以string类的形式出现,而且在常规工作中,为了简单、方便、快捷,基本都使用string类,很少有人去使用C库中的字符串操作函数。


二、 string类的简介

文档查阅链接:string - C++ Reference

如图是在文档中对string的部分介绍。简单总结一下就是:

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

三、string的库中常见使用

        string类中的可以使用的函数有许多,本次的使用讲解只是将库中常见使用进行列举,来逐渐掌握string的使用。

1. 常见构造函数

库中的构造函数有:

其中的所有函数在文当中都有解释,链接为:string::string - C++ Reference

现在来看看string类的实例化,测试代码:

#include<string>
#include <iostream>
using namespace std;void test1()
{string s1; //  默认构造函数:string();string s2("Hello world"); // 用C字符串来构造string类对象string s3(s2); // 拷贝构造string s4(10, 'x'); // string类对象中包含10个字符xstring s5("Hello world", 4); // 复制"Hello world"的前4个string s6(s2, 4, 3); // 复制s2对象的下标为4的位置开始的后面3个字符// 复制s2对象的下标为3的位置开始的后面100个字符,此时s2长度不够,// 则会使用缺省参数npos = -1,将剩余的字符全部拷贝string s7(s2, 3, 100);cout << "s1:" << s1 << endl;cout << "s2:" << s2 << endl;cout << "s3:" << s3 << endl;cout << "s4:" << s4 << endl;cout << "s5:" << s5 << endl;cout << "s6:" << s6 << endl;cout << "s7:" << s7 << endl;
}
int main()
{test1();return 0;
}

除此之外,还可以使用赋值运算符重载来实例化:

链接:string::operator= - C++ Reference

它可以使用string对象,C字符串,和字符来进行赋值:

#include<string>
#include <iostream>
using namespace std;
void test2()
{string s1("Hello world");string s2;s2 = s1;cout << s2 << endl; // string& operator= (const string& str);s2 = "abcdefg";cout << s2 << endl; // string& operator= (const char* s);s2 = 'x';cout << s2 << endl; // string& operator= (char c);}int main()
{test2();return 0;
}

2. 对容量的操作

在库中常见对容量的操作如下:

对于size、length、capacity,都是没参数的,且都只有一个函数,使用时需要注意:

  • size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()。
  • clear()只是将string中有效字符清空,不改变底层空间大小(即:capacity不会变)。

使用代码如下:

#include<string>
#include <iostream>
using namespace std;
void test3()
{string s1("Hello world");cout << "s1 :"<< s1 << endl;cout << "s1.size():" << s1.size() << endl;cout << "s1.length():" << s1.length() << endl;cout << "s1.capacity():" << s1.capacity() << endl;s1.clear();cout << "-----------执行s1.clear()后-------------" << endl;cout << "s1 :" << s1 << endl;cout << "s1.size():" << s1.size() << endl;cout << "s1.length():" << s1.length() << endl;cout << "s1.capacity():" << s1.capacity() << endl;
}
int main()
{test3();return 0;
}

对empty和clear进行测试:

使用:

#include<string>
#include <iostream>
using namespace std;
void test4()
{string s1("Hello world");cout << "s1:" << s1 << endl;cout << "s1.size():" << s1.size() << endl;cout << "s1.capacity():" << s1.capacity() << endl;cout << "s1.empty():" << s1.empty() << endl;s1.clear();// 清除s1中的数据,但容量不变cout << "s1:" <<s1 << endl;cout << "s1.size():" << s1.size() << endl;cout << "s1.capacity():" << s1.capacity() << endl;cout << "s1.empty():" << s1.empty() << endl;
}
int main()
{test4();return 0;
}

对于resize,有多个函数,来看库中:

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

使用代码如下:

#include<string>
#include <iostream>
using namespace std;
void test5()
{string s1("Hello world");cout << "s1:" << s1 << endl;cout << "s1.size():" << s1.size() << endl;cout << "s1.capacity():" << s1.capacity() << endl << endl;s1.resize(5);//n比当前长度小cout << "s1:" << s1 << endl;cout << "s1.size():" << s1.size() << endl;cout << "s1.capacity():" << s1.capacity() << endl << endl;s1.resize(10, 'x');//n比当前长度大,并且指定字符xcout << "s1:" << s1 << endl;cout << "s1.size():" << s1.size() << endl;cout << "s1.capacity():" << s1.capacity() << endl << endl;s1.resize(100);//n比当前长度大,不指定字符cout << "s1:" << s1 << endl;cout << "s1.size():" << s1.size() << endl;cout << "s1.capacity():" << s1.capacity() << endl << endl;
}
int main()
{test5();return 0;
}

可以扩容的还有一个函数reserve,在库中只有一个函数:

        reserve(size_t n = 0) :为string预留空间,不改变有效元素个数,当n小于string的底层空间总大小时,reserver不会改变容量大小;如果n大于当前的字符串容量,该函数会促使容器将其容量增加到n个字符或更大(不同平台,扩容的大小可能不同)。

使用代码如下:

#include<string>
#include <iostream>
using namespace std;
void test6()
{string s1("Hello world");cout << "s1.size():" << s1.size() << endl;cout << "s1.capacity():" << s1.capacity() << endl << endl;s1.reserve(5);//n比当前长度小cout << "s1:" << s1 << endl;cout << "s1.size():" << s1.size() << endl;cout << "s1.capacity():" << s1.capacity() << endl << endl;s1.reserve(50);//n比当前长度大cout << "s1.size():" << s1.size() << endl;cout << "s1.capacity():" << s1.capacity() << endl << endl;
}
int main()
{test6();return 0;
}

3. 访问及遍历操作

对对象进行访问及遍历的常用函数:

(1)常见操作

        在C语言阶段,我们常常是使用方括号+下标([ ]+下标)的方法来遍历字符数组的,在C++中,也是可以这样写的:

#include<string>
#include <iostream>
using namespace std;
void test7()
{// C语言char str[] = "Hello world";str[1]++; // C++string s1("Hello world");for (size_t i = 0; i < s1.size(); i++){cout << s1[i] << ' ';}cout << endl;
}int main()
{test7();return 0;
}

其实C++中的 [ ] + 下标是 [ ] 操作符重载:s1[i] -->  s1.operator[ ](i)   

“char& operator[] (size_t pos);”o普通对象可以使用;

“const char& operator[] (size_t pos) const;”普通对象和const对象都可以使用。

(2)string的迭代器

        在C++中,std::string 的迭代器是一种用于遍历和访问字符串中字符的对象。迭代器提供了类似于指针的功能,允许你逐个访问字符串中的每个字符。迭代器可能是指针,也可能不是指针,在string中的迭代器其实就是指针。

begin() 和 end():

  • begin() 返回指向字符串第一个字符的迭代器。
  • end() 返回指向字符串末尾(最后一个字符的下一个位置)的迭代器。

rbegin() 和 rend():

  • rbegin() 返回指向字符串最后一个字符的反向迭代器。
  • rend() 返回指向字符串开头之前的反向迭代器。

iterator是像指针一样的类型,有可能是指针,也可能不是指针;iterator是正向的迭代器,而reverse_iterator则是反向的迭代器。要注意:const_iterator和const_reverse_iterator类型的迭代器都是只能读不能写的。

        它的使用方法如下:

#include<string>
#include <iostream>
using namespace std;
void test8()
{string s1("Hello world");string::iterator it = s1.begin();while (it != s1.end()){cout << *it << " ";++it;}cout << endl;// 反向迭代器:反向打印string::reverse_iterator rit = s1.rbegin();while (rit != s1.rend()){// 读cout << *rit << " ";++rit;}cout << endl;
}
int main()
{test8();return 0;
}

返回for也是可以实现访问遍历的,如果是要对数据进行修改,则要用引用,如下所示:

#include<string>
#include <iostream>
using namespace std;
int main()
{string s1("Hello world");for (auto& ch : s1){//改ch++;}for (auto ch : s1){//读cout << ch << " ";}return 0;
}

其实范围for的底层是用迭代器实现的。

4. string类对象的增加操作

对对象进行修改的常用函数:

对于push_back,在库中只有一个函数:

使用如下:

#include<string>
#include <iostream>
using namespace std;
int main()
{string s1("Hello world");s1.push_back('x');s1.push_back('y');s1.push_back('z');cout << s1 << endl;return 0;
}

对于append,在库中有:

代码的使用:

#include<string>
#include <iostream>
using namespace std;
void test9()
{string s1("Hello world");string s2("abcdefgh");s1.append(s2);cout << s1 << endl;string s3("Hello world");s3.append(s2,3,4);cout << s3 << endl;string s4("Hello world");s4.append("1234567");cout << s4 << endl;string s5("Hello world");s5.append("1234567", 3);cout << s5 << endl;string s6("Hello world");s6.append(3, 'x');cout << s6 << endl;
}
int main()
{test9();return 0;
}

对于oprevator+=,在库中有:

可以追加的有:string对象中的字符串,常量字符串,单个字符。并且它还可以自己根据条件扩容的

#include<string>
#include <iostream>
using namespace std;
void test10()
{string s1("Hello world");string s2("abcdefgh");s1 += s2;cout << s1 << endl;string s3("Hello world");s3 += "123456789";cout << s3 << endl;string s4("Hello world");s4 += 'x';cout << s4 << endl;
}
int main()
{test10();return 0;
}

        在string尾部追加字符时,s.push_back(c) / s.append(1, c) / s += 'c'三种的实现方式差不多,一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。

上面三种都是在原数据上进行追加,还可以指定位置进行插入,可以使用insert函数。它的函数重载也有很多:

我们以其中的第2个为例,是在pos位置插入str对象中的字符串中的从第subpos位置开始的sublen个字符:

#include<string>
#include <iostream>
using namespace std;
int main()
{string s1("Hello world");string s2("0123456789");s1.insert(5, s2, 3, 8);  // 向s1中的第5个下标位置插入s2的下标为3开始的后8个字符cout << s1 << endl;return 0;
}

其余的重载函数可以根据文档进行查阅:string::insert - C++ Reference

5. 对string对象进行查找

常用函数有:

c_str可以返回C格式的字符串的指针,在C++中如果想用一些只能用C语言的字符串接口,就可以使用c_str来转化。

对于find的库函数有:

这里只介绍一种,比如第一个,给了缺省值0,它是在这个成员函数调用的对象中向后去找与str对象中的字符串匹配的子字符串的首次出现位置。找到后就返回。如果没找到,就返回npos。npos是string的静态成员变量,在库中是:

npos是无符号类型,并且默认值为-1。返回时会转化为全1的二进制,所以返回的就是最大的整型

void test11()
{string s1("Hello world");string s2("world");string s3("well");cout << s1.find(s2, 0) << endl;cout << s1.find(s3, 0) << endl; 
}
int main()
{test11();return 0;
}

运行结果:

find是向后查找,而也有一个向前查找的函数rfind:

这里我们也只开看第一个:

对于substr,在库中可以看到:

它的功能是在当前对象中从pos位置开始,截取n个字符,然后将其返回

6. string类非成员函数

几个常用的非成员函数:

库中operator+中函数重载有:

它常常是用来连接对象中的字符串的。如以下代码所示:

void test12()
{string s1("Hello");string s2(" ");string s3("world");string s4;s4 = s1 + s2 + s3;cout << s4 << endl;
}
int main()
{test12();return 0;
}

运行之后就是Hello world。

对应对流插入和流提取的运算符重载由于是在string这个头文件中实现了的,所以才会支持string这个类的对象的输入输出。它们的使用方式和内置类型是几乎相同的。

对于getline,在库中:

第一个:从输入流 is 中读取数据到字符串 str,直到遇到分隔符 delim。分隔符 delim 会被提取但不会被存储到 str 中。

第二个:从输入流 is 中读取数据到字符串 str,直到遇到换行符 '\n'。换行符会被提取但不会被存储到 str 中。

对于字符串时可以比较大小的,对于string类也是一样,所以在库中就会有对其进行比较大小的函数:

它们和str系列中的strcmp差不多,都是按照其ASCLL码来比较的。


四、总结

        以上内容是关于string中的常见库函数的使用,虽然并没有完全介绍,但介绍了一些常见的使用函数,算是对string类进行了初步了解了,关于string的有关的函数还有很多,如下图所示:

如果要更加深入的使用string类中的,可以根据文档来进一步学习了解,C++文档链接:string - C++ Reference

感谢各位观看!希望能多多支持!


文章转载自:

http://O6t1YKkI.xnnpy.cn
http://3WKHUiXS.xnnpy.cn
http://6YnBNs6e.xnnpy.cn
http://fXLn1U9q.xnnpy.cn
http://0QItjgTK.xnnpy.cn
http://yoHAwTum.xnnpy.cn
http://GIYiOXR8.xnnpy.cn
http://8GpC0u6g.xnnpy.cn
http://1DVhv47a.xnnpy.cn
http://7CxTxvrW.xnnpy.cn
http://PPUpLcoD.xnnpy.cn
http://ncoCubKF.xnnpy.cn
http://Oah1ONpf.xnnpy.cn
http://bEEkB1vx.xnnpy.cn
http://09eXmitZ.xnnpy.cn
http://aScyLwpW.xnnpy.cn
http://kQsGeLa3.xnnpy.cn
http://O6vySWsE.xnnpy.cn
http://uBZB222P.xnnpy.cn
http://NSv6rkVN.xnnpy.cn
http://JeHLWfkV.xnnpy.cn
http://7zpd7jlK.xnnpy.cn
http://c1Wep7gs.xnnpy.cn
http://iPZn3nnj.xnnpy.cn
http://tmQBzl19.xnnpy.cn
http://0Iq0FJay.xnnpy.cn
http://JScAVUf7.xnnpy.cn
http://ZcV2pZek.xnnpy.cn
http://QZYY8gsg.xnnpy.cn
http://4JU99xqu.xnnpy.cn
http://www.dtcms.com/a/375804.html

相关文章:

  • Go语言基础---数据类型间的故事
  • 金融量化指标--6InformationRatio信息比率
  • GPT Server 文档
  • CDN加速带来的安全隐患及应对方法
  • HCL Unica+:AI驱动的营销自动化与个性化平台
  • spring事务管理之@Transactional
  • golang之go modules
  • 设计UIUC SE 423机电一体化的机器人
  • 《Vuejs设计与实现》第 15 章(编译器核心技术)上
  • (二)文件管理-文件查看-more命令的使用
  • IntelliJ IDEA双击Ctrl的妙用
  • cfshow-web入门-php特性
  • libvirt 新手指南:从零开始掌握虚拟化管理
  • Oracle打补丁笔记
  • 【JavaEE】(24) Linux 基础使用和程序部署
  • TENGJUN防水TYPE-C连接器:工业级防护,认证级可靠,赋能严苛场景连接
  • Spring MVC 的常用注解
  • 肺炎检测系统
  • ctfshow-web-SSTI模版注入
  • RHEL 10 更新 rescue kernel
  • Vue3 + Vite + Element Plus web转为 Electron 应用,解决无法登录、隐藏自定义导航栏
  • 记SpringBoot3.x + SpringSecurity6.x之session管理
  • Pinia 两种写法全攻略:Options 写法 vs Setup 写法
  • 项目管理系统高保真原型案例:剖析设计思路与技巧
  • 第2节-过滤表中的行-DELETE
  • 基于AI的未佩戴安全帽检测算法
  • webpack打包方式
  • 第2节-过滤表中的行-WHERE
  • linux内核 - 内核是一个分层的系统
  • 基于Multi-Transformer的信息融合模型设计与实现