【C++深入浅出】STL之string用法详解


目录

一. 前言

二. STL概要

2.1 什么是STL

2.2 STL的六大组件

2.3 STL的缺陷

三. string类概述

3.1 什么是string类

3.2 为什么要使用string类

四. string类的使用

4.1 包含头文件

4.2 构造函数

4.3 赋值运算符重载

4.4 容量操作

4.5 访问/遍历操作

4.6 查找修改操作

4.7 子串操作

​4.8 非成员函数


一. 前言

        经历了前面漫长且痛苦的学习,相比各位已经体会到了C++的魅力了叭 不要怕,学习完了模板之后,下面我们将进入STL的学习。相信你学完了STL之后,就会感受到使用C++是多么的顺畅,你甚至会不想回到使用C语言的时期,不信?就让我们拭目以待叭

二. STL概要

2.1 什么是STL

        把STL说得那么神,那STL究竟是什么呢?

        STL(standard template libaray - 标准模板库)C++标准库的重要组成部分。其不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架。有了STL后,像先前我们写的链表、顺序表、排序算法等等常见的底层数据结构和算法我们就可以不用自己造轮子了,我们可以站在前人的肩膀上,快速的进行开发。

2.2 STL的六大组件

        STL主要由以下六大组件构成:

        在后续的学习中,我们会逐个接触到,到时我们在进行详细讲解。

2.3 STL的缺陷

        尽管STL功能十分强大,但也存在着一些缺陷,下面我们列出了几点:

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

三. string类概述

3.1 什么是string类

        string是C++标准库中用来表示字符序列的类,其中包含了许多关于操作单字节字符串的接口。string在底层实际上是basic_string模板类的别名,如下所示:

typedef basic_string<char, char_traits, allocator> string;

        可以看到,string是basic_string类模板的一个实例,其用char来实例化basic_string类模板,即string中存储的数据类型是char类型。故string只能用于处理单字节的序列,不能操作多字节或者变长字符的序列。

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

3.2 为什么要使用string类

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

四. string类的使用

4.1 包含头文件

        首先,要使用string类,我们需要包含<string>头文件,并且由于string定义在命名空间std中,我们还需使用命名空间std,如下所示:

#include<string>
using namespace std;

接下来,我们将逐一介绍string的一些常用接口,由于string的接口以及重载版本非常多,详情读者可以参考以下链接:string - C++ Reference (cplusplus.com)icon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/?kw=string

4.2 构造函数

        string也是个类,使用类时我们首先关注的就是它的构造函数,string常见的构造函数如下所示:

        使用方式如下所示: 

void test_constructor()
{
	string str1; //无参构造
	string str2("abcd"); //C字符串构造
	string str3(str2); //拷贝构造
	string str4(str3, 1, 2); //子串构造
	string str5(str2.begin(), str2.begin()+3); //迭代器构造
}

这里有个小问题:在子串构造中,npos的含义又是什么呢?它的定义如下:

static const size_t npos = -1;

由于size_t是无符号整形,而-1在内存中二进制表示为全1,故将-1赋值给npos后npos实际上是2^32-1,是一个非常大的数。

而string规定如果指定的长度len超过字符串的长度则只截取到字符串末尾,故将len的缺省值设置为npos的作用是当用户没有指定子串长度时默认截取到字符串末尾。

4.3 赋值运算符重载

        string重载了赋值运算符以便我们进行两个string对象之间的赋值,函数原型及说明如下所示:

         使用方式如下所示:

void test_assign()
{
	string str1("abcd");
	string str2 = "ab"; //注意,这里不是赋值重载,这里是定义并初始化str2,故调用的是构造函数
	str2 = str1; //这里才是赋值重载,用string对象赋值
	str2 = "aaaa"; //用一个C字符串赋值
	str2 = 'c'; //用一个字符赋值,此时str2的长度变为1
}

4.4 容量操作

        string类提供了许多与字符串容量相关的接口,如下表所示:

下面有几点注意事项

  1. size()与length()方法底层实现原理完全相同,string出现得比STL早,那时string只有length方法,后面引入size()的原因是为了与其他STL容器的接口保持一致,一般情况下基本都是用size()
  2. clear只是把有效字符的个数清空,不会改变底层空间的大小。
  3. reverse()的作用是为string保留空间,其不改变有效元素个数,当reserve的参数n小于
    string的底层总容量大小时,reserver不会改变容量大小。
  4. 使用reverse()时,有时编译器实际分配的大小会比我们指定的空间,这取决于编译器,不过并不会造成什么影响,我们无需过多关心。

         使用方式如下所示: 

void test_capacity()
{
	string str1 = "hello world";
	cout << "size : " << str1.size() << endl; //输出有效字符长度
	cout << "lenfth : " << str1.size() << endl;
	cout << "capacity : " << str1.capacity() << endl; //输出当前的总容量
	str1.resize(5); //重新指定有效字符的长度
	cout << "size : " << str1.size() << endl;
	str1.reserve(20); //为字符串保留长度为20的空间
	cout << "capacity : " << str1.capacity() << endl;
	cout << "size : " << str1.size() << endl;
	str1.clear(); //清空有效字符
	cout << "empty : " << str1.empty() << endl; //判断字符串是否为空
	cout << "size : " << str1.size() << endl;
}

4.5 访问/遍历操作

        访问操作 

        遍历操作

        通过上面的操作,我们就可以轻松地对一个string对象进行遍历访问了,至于迭代器是什么,目前我们可以把它当做一个原生指针来使用,后面我们再进行详细介绍。元素访问和遍历的演示如下所示:

void  test_access()
{
	string str1("hello world");
	cout << "front : " << str1.front() << endl;
	cout << "back : " << str1.back() << endl;

	cout << "下标遍历:" << endl;
	for (int i = 0; i < str1.size(); i++)
	{
		cout << str1[i];
	}
	cout << endl;

	cout << "正向迭代器遍历:" << endl;
	string::iterator it = str1.begin();      //iterator类型在string的类域中,要加作用域限定符
	//auto it = str1.begin();  //也可以使用auto自动推导类型
	while (it != str1.end())
	{
		cout << *it;  //可以看做原生指针使用
		it++;
	}
	cout << endl;

	cout << "反向迭代器遍历:" << endl;
	string::reverse_iterator rit = str1.rbegin();      //反向迭代器的类型为reverse_iterator
	while (rit != str1.rend())
	{
		cout << *rit;  //可以看做原生指针使用
		rit++;
	}

	cout << "范围for遍历:" << endl; 
	for (auto e : str1)
	{
		cout << e;
	}
}

注意事项:

  1. 由于迭代器类型是在类域内进行重定义的,故我们要使用作用域限定符::指定其类域。
  2. 对于[ ]运算符和at方法,一般更喜欢使用[ ]进行访问,原因方括号更简便且顺手。
  3. 范围for遍历的实现原理实际上就是替换编译器会自动将范围for的代码替换为迭代器进行遍历。我们可以调试并对比二者的汇编验证:

4.6 查找修改操作

         和C语言的常量字符串相比,C++的string对象是可修改的,string类中的字符串是保存在堆空间上的。下面是string类中一些常见的查找和修改接口:

        查找操作

        使用方式如下所示: 

void test_find()
{
	string str1("hello world hello");
	string str2("hello");
	char ch = 'o';
	cout << "从前往后str2第一次出现的下标为:" << str1.find(str2) << endl;
	cout << "从前往后ch第一次出现的下标为:" << str1.find(ch) << endl;
	cout << "从后往前str2第一次出现的下标为:" << str1.rfind(str2) << endl;
	cout << "从后往前ch第一次出现的下标为:" << str1.rfind(ch) << endl;
}

        修改操作

        使用方式如下所示: 

void test_modify()
{
	string str1("hello");
	str1 += "world";
	cout << str1 << endl;
	str1.push_back('!'); //尾插单字符
	cout << str1 << endl;
	str1.append("haha");  //追加字符串
	cout << str1 << endl;

	string str2("hehe");
	str1.swap(str2); //交换
	cout << "str1 = " << str1 << endl;
	cout << "str2 = " << str2 << endl;
}

注意事项:

        一般我们在进行插入时,使用+=运算符会比较多,因为+=不仅可以用来插入字符,也可以用来插入字符串。

4.7 子串操作

        除此之外,string类还有两个较常用的接口,一个用于快速截取子串,一个用来获取C格式的字符串,如下所示:

        使用方式如下所示: 

void test_substr()
{
	string str1 = "hello world";
	string str2 = str1.substr(1, 8);  //截取从下标1处到下标8处的子串  
	cout << str2 << endl;
	cout << str2.c_str() << endl;  //获取C格式的字符串
}

4.8 非成员函数

        最后,除了上面定义在string类内的成员函数,C++还定义了一些全局函数对string对象进行操作,典型的例子就是我们的流提取(>>)流插入(<<)运算符,这两个只能作为全局函数重载。具体的一些接口如下所示:

        使用方式如下所示: 

void test_general()
{
	string str1, str2;
	cout << "请输入一个字符串 :";
	cin >> str1;
	cout << "str1 = " << str1 << endl;
	cin.get();    //这里输入流中会剩下一个'\n',用get方法读取掉,否则getline遇到'\n'会直接停下来
	cout << "请输入一个字符串 :";
	getline(cin, str2);
	cout << "str2 = " << str2 << endl;

	if (str1 > str2)
		cout << "str1 > str2";
	else if(str1 < str2)
		cout << "str1 < str2";
	else 
		cout << "str1 == str2";
}


 以上,就是本期的全部内容啦🌸

制作不易,能否点个赞再走呢🙏

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JavaEE平台技术——Spring和Spring Boot

JavaEE平台技术——Spring和Spring Boot 1. 控制反转1.1. IoC是什么1.2. IoC能做什么1.3. IoC和DI 2. SpringBean对象定义3. Spring容器4. SpringBoot 在观看这个之前&#xff0c;大家请查阅前序内容。 &#x1f600;JavaEE的渊源 &#x1f600;&#x1f600;JavaEE平台技术——…

基于SSM的网吧计费管理系统(有报告)。Javaee项目,ssm项目。

演示视频&#xff1a; 基于SSM的网吧计费管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通…

基于SSM的教学管理系统(有报告)。Javaee项目。

演示视频&#xff1a; 基于SSM的教学管理系统&#xff08;有报告&#xff09;。Javaee项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring SpringMvc My…

自动化测试之争:code vs codeless

在TesterHome看到的一个话题&#xff0c;当我们选择做自动化时是否需要code 或者codeless。 code方案 用code去做自动化&#xff0c;实现过程就是拿个IDE撸代码。 python pytest/unittest appium/selenium/requests ... Java Junit/testNG appium/selenium/requests .…

go测试库之apitest

前言 使用go语言做开发差不多快一年了&#xff0c;主要用来写后端Web服务&#xff0c;从一开始吐槽他的结构体&#xff0c;比如创建个复杂的JSON格式数据&#xff0c;那是相当的痛苦。还有 err 处理写的巨麻烦。 当然&#xff0c;go 也有爽的地方&#xff0c;创建个线协程简直…

Compose-Multiplatform在Android和iOS上的实践

本文字数&#xff1a;4680字 预计阅读时间&#xff1a;30分钟 01 简介 之前我们探讨过KMM&#xff0c;即Kotlin Multiplatform Mobile&#xff0c;是Kotlin发布的移动端跨平台框架。当时的结论是KMM提倡将共有的逻辑部分抽出&#xff0c;由KMM封装成Android(Kotlin/JVM)的aar和…

Spring Cloud分布式缓存

目录 单点Redis Redis数据持久化 RDB持久化 bgsave细节 RDB的缺点 AOF持久化 AOF的问题 RDB与AOF对比 搭建Redis主从架构 数据同步原理 全量同步 增量同步 主从同步优化 Redis哨兵 集群检测 选举主节点 故障转移 搭建哨兵集群 RedisTemplate的哨兵模式 单点…

ConcurrentHashMap是如何实现线程安全的

目录 原理&#xff1a; 初始化数据结构时的线程安全 put 操作时的线程安全 原理&#xff1a; 多段锁cassynchronize 初始化数据结构时的线程安全 在 JDK 1.8 中&#xff0c;初始化 ConcurrentHashMap 的时候这个 Node[] 数组是还未初始化的&#xff0c;会等到第一次 put() 方…

【Java】三种方案实现 Redis 分布式锁

序言 setnx、Redisson、RedLock 都可以实现分布式锁&#xff0c;从易到难得排序为&#xff1a;setnx < Redisson < RedLock。一般情况下&#xff0c;直接使用 Redisson 就可以啦&#xff0c;有很多逻辑框架的作者都已经考虑到了。 方案一&#xff1a;setnx 1.1、简单实…

PDF 表单直接保存到您的文档中--TX Text Control

TX Text Control .NET Server for ASP.NET Document Viewer 32.0.2 允许用户保存包含已填写表单字段的文档&#xff0c;从而更轻松地协作和共享信息。 TX Text Control .NET Server for ASP.NET 是一个适用于 ASP.NET 和 ASP.NET Core 的综合服务器端文档处理库。功能包括 PDF …

程序员笔记本电脑选 windows 还是 MAC

计算机选择是每个进入 IT 行业同学的第一个重要选择&#xff0c;那么你是怎么选择的呢&#xff1f; 选择操作系统&#xff08;Windows还是macOS&#xff09;取决于程序员的需求、偏好和工作流程。每个操作系统都有其优点和缺点&#xff0c;下面将分别讨论它们&#xff0c;以帮助…

volatile-无原子性案例详解

package com.nanjing.gulimall.zhouyimo.controller;import java.util.concurrent.TimeUnit;/*** author zhou* version 1.0* date 2023/11/5 7:56 下午*/ class MyNumber{int number;public synchronized void add(){number;} } public class VolatileNoAtomicDemo {public st…

gcc -static 在centos stream8 和centos stream9中运行报错的解决办法

gcc -static 在centos stream8 和centos stream9中运行报错的解决办法&#xff1a; 报/usr/bin/ld: cannot find -lc 我们下载glibc-static&#xff1a; 选择x86_64的。 还有一个是libxcrypt-static&#xff0c;依旧在这个网站里搜。 rpm -ivh glibc-static-2.28-239.el8.x…

排序——冒泡排序

冒泡排序的基本思想 从前往后&#xff08;或从后往前&#xff09;两两比较相邻元素的值&#xff0c;若为逆序&#xff08;即 A [ i − 1 ] < A [ i ] A\left [ i-1\right ]<A\left [ i\right ] A[i−1]<A[i]&#xff09;&#xff0c;则交换它们&#xff0c;直到序列…

【Linux】多路IO复用技术③——epoll详解如何使用epoll模型实现简易的一对多服务器(附图解与代码实现)

在正式阅读本篇博客之前&#xff0c;建议大家先按顺序把下面这两篇博客看一下&#xff0c;否则直接来看这篇博客的话估计很难搞懂 多路IO复用技术①——select详解&如何使用select模型在本地主机实现简易的一对多服务器http://t.csdnimg.cn/BiBib多路IO复用技术②——poll…

Web3游戏的十字路口:沿用传统IP还是另起炉灶?

人们经常问我对 Web3 游戏有什么看法。因此&#xff0c;我想以书面形式概述一下我目前的想法。 让我先澄清一下&#xff1a;我不是专家。这不是一篇深入探讨游戏世界精细指标如 MAU 或 D14 等的全面分析。请把这看作是我根据个人交流和研究&#xff0c;这反映我在游戏领域关注…

java代码检查

目录 jacoco 引入依赖 构建配置修改 单元测试 生成报告 查看报告 报告说明 1. Instructions 2. Branches 3. Cyclomatic Complexity 4. Lines 5. Methods 6. Classes sonar7.7 基础环境 需要下载软件 解压文件并配置 运行启动 jacoco 引入依赖 <dep…

jenkins安装以及基本配置

一、docker 1.安装docker 联网安装命令如下 curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun或者也可以使用国内 daocloud 一键安装命令&#xff1a; curl -sSL https://get.daocloud.io/docker | sh2.启动docker systemctl start docker二、docker…

pycharm更改远程服务器地址

一、问题描述 在运行一些项目时&#xff0c;我们常需要在pycharm中连接远程服务器&#xff0c;但万一远程服务器的ip发生了变化&#xff0c;该如何修改呢&#xff1f;我们在file-settings-python interpreter中找到远程服务器&#xff0c;但是发现ip是灰色的&#xff0c;没有办…

Azure 机器学习 - 使用 Visual Studio Code训练图像分类 TensorFlow 模型

了解如何使用 TensorFlow 和 Azure 机器学习 Visual Studio Code 扩展训练图像分类模型来识别手写数字。 关注TechLead&#xff0c;分享AI全维度知识。作者拥有10年互联网服务架构、AI产品研发经验、团队管理经验&#xff0c;同济本复旦硕&#xff0c;复旦机器人智能实验室成员…