【C++】STL——string的使用

news2024/11/26 18:31:05

大家好我是沐曦希💕

文章目录

  • 一、STL简介
    • 1.STL版本
    • 2.STL的组成
    • 3.如何学习STL
  • 二、编码
  • 三、string类
  • 四、常见构造
  • 五、operator[]
  • 六、iterator迭代器
    • 1.正向迭代器
    • 2.反向迭代器
    • 3.const迭代器
  • 七、Capacity容量操作
    • 1.接口
    • 2.扩容
  • 八、Modifiers修改操作
  • 九、非成员函数重载


在这里插入图片描述

一、STL简介

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

网上有句话说:“不懂STL,不要说你会C++”。STL是C++中的优秀作品,有了它的陪伴,许多底层的数据结构以及算法都不需要自己重新造轮子,站在前人的肩膀上,健步如飞的快速开发。

1.STL版本

  • 原始版本
    Alexander Stepanov、Meng Lee 在惠普实验室完成的原始版本,本着开源精神,他们声明允许任何人任意运用、拷贝、修改、传播、商业使用这些代码,无需付费。唯一的条件就是也需要向原始版本一样做开源使用。 HP 版本–所有STL实现版本的始祖。
  • P. J. 版本
    由P. J. Plauger开发,继承自HP版本,被Windows Visual C++采用,不能公开或修改,缺陷:可读性比较低,符号命名比较怪异。
  • RW版本
    由Rouge Wage公司开发,继承自HP版本,被C+ + Builder 采用,不能公开或修改,可读性一般。
  • SGI版本
    由Silicon Graphics Computer Systems,Inc公司开发,继承自HP版 本。被GCC(Linux)采用,可移植性好,可公开、修改甚至贩卖,从命名风格和编程 风格上看,阅读性非常高。后面的学习主要参考的就是这个版本。

2.STL的组成

在这里插入图片描述

3.如何学习STL

  • 在线网站

cplusplus.com - The C++ Resources Network
在这里插入图片描述
便于查找各种接口,函数的功能,参数等信息详细列出,更适合初学者。

官方网站: cppreference.com
在这里插入图片描述

  • 书籍

阅读C++方向优秀的书籍便于我们理解和应用C++:《C++ Primer 中文版(第 5 版)》、《STL源码剖析》

二、编码

string类是管理字符串的数组的类,因为字符串的编码的不同,所以string也是一个模板。

u16string:表示两个字节
u32string:表示四个字节

  • ASCII码值

美国信息交换标准码。
ASCII码表是计算机存值和文字符号的对应关系
只有256个字符
在这里插入图片描述

  • Unicode(万国码)

统一码是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。

包括了utf-8,utf-16,utf-32

utf-8兼容了ASCII,utf-8使用比较普遍,也比较节省空间

  • GBK字库

gbk即国标,针对中文而设计的编码。采用双字节编码。

三、string类

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

基于上面这些原因,C++标准库提供了 string 类,string 类中提供了各种函数接口,比如类的六个默认成员函数、字符串插入删除、运算符重载等等,我们可以使用 string 来实例化对象,然后通过 string 的各种接口来完成对该对象的各种操作。

基本框架:

namespace std
{
	template<class T>
	class basic_string
	{
	public:
		//string成员函数
	private:
		T* _str;
		size_t _size;
		size_t capacity;
		//string的成员变量
	};
}

根据不同的编码选用不同的string(接口是差不多的),这里我们只需重点学习string(utf-8), 其实string 出现的时间比 STL 要早,导致string的函数参数命名方式很多与其他STL的容器不同。
在这里插入图片描述

在使用string类时,必须包含#include头文件以及using namespace std;

  1. 字符串是表示字符序列的类
  2. 标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作单字节字符字符串的设计特性。
  3. string类是使用char(即作为它的字符类型,使用它的默认char_traits和分配器类型(关于模板的更多信息,请参阅basic_string)。
  4. string类是basic_string模板类的一个实例,它使用char来实例化basic_string模板类,并用char_traits和allocator作为basic_string的默认参数(根于更多的模板信息请参考basic_string)。
  5. 注意,这个类独立于所使用的编码来处理字节:如果用来处理多字节或变长字符(如UTF-8)的序列,这个类的所有成员(如长度或大小)以及它的迭代器,将仍然按照字节(而不是实际编码的字符)来操作。

总结:

  1. string是表示字符串的字符串类
  2. 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
  3. string在底层实际是:basic_string模板类的别名,typedef basic_string<char, char_traits, allocator>string;
  4. 不能操作多字节或者变长字符的序列。

四、常见构造

在这里插入图片描述

(constructor)函数名称功能说明
string() (重点)构造空的string类对象,即空字符串
string(const char* s) (重点)用C-string来构造string类对象
string(size_t n, char c)string类对象中包含n个字符c
string(const string&s) (重点)拷贝构造函数
#include<string>
#include<iostream>
using namespace std;
int main()
{
	string s1;// 构造空的string类对象s1
	cout << s1 << endl;
	string s2("hello world");// 用C格式字符串构造string类对象s2
	cout << s2 << endl;
	string s3("hello world", 2, 5);//在pos位置向后取n个
	cout << s3 << endl;
	string s4("hello world", 5);//取前n个
	cout << s4 << endl;
	string s5(10, 'c');//个数初始化
	cout << s5 << endl;
	string s6(s3);// 拷贝构造s4
	cout << s6 << endl;
	return 0;
}

在这里插入图片描述

注意:string类对象可支持直接用cin和cout进行输入和输出,这是因为重载了流插入>>和流提取<<操作符

对于s3,如果pos+n 大于前面字符串的长度
在这里插入图片描述
直到结束,并不会报错:
在这里插入图片描述
对于string::npos
在这里插入图片描述
它的值是-1,但是它的类型是size_t(无符号整型),所以它的真实值是整型的最大值4294967295。

五、operator[]

返回pos位置的字符,const string类对象调用。
重载了[],用法类似于数组,数组的[]的本质是解引用,而这里是调用函数:
在这里插入图片描述

char& operator[](size_t pos)//可读,返回值可修改
{
	assert(pos < _size);
	return _str[pos];
}
const char& operator[](size_t pos) const//只能读,返回值不能修改
{
	assert(pos < _size);
	return _str[pos];
}

传引用返回,可读可改。支持修改返回值:

void test_string2()
{
	string s1("1234567");
	size_t i = 0;
	for (i = 0; i < s1.size(); ++i)
	{
		cout << s1[i] << " ";
	}
	cout << endl;
	for (i = 0; i < s1.size(); ++i)
	{
		s1[i] += 1;
	}
	cout << s1 << endl;
	//反转
	size_t begin = 0;
	size_t end = s1.size() - 1;
	while (begin < end)
	{
		swap(s1[begin++], s1[end--]);
	}
	cout << s1 << endl;
}

在这里插入图片描述

六、iterator迭代器

迭代器行为上像指针,但是却不一定是指针。比如list中迭代器不是指针

typedef char* iterator

迭代器作用:

迭代器的意义在于通用,所有容器都可以使用迭代器这种方式去进行遍历和修改。而对于string类,[]足矣

函数名称功能说明
begin+ endbegin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器
rbegin + rendbegin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器
范围forC++11支持更简洁的范围for的新遍历方式

1.正向迭代器

在这里插入图片描述
end()返回的迭代器指向的是字符串末尾的’\0’
在这里插入图片描述

void test_string3()
{
	string s1("123456");
	string::iterator it = s1.begin();
	while (it != s1.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
	it = s1.begin();
	while (it != s1.end())
	{
		*it += 1;
		++it;
	}
	cout << s1 << endl;
}

在这里插入图片描述

2.反向迭代器

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

void test_string4()
{
	string s1("123456");
	string::reverse_iterator it = s1.rbegin();
	while (it != s1.rend())
	{
		*it += 1;
		++it;
	}
	cout << s1 << endl;
}

在这里插入图片描述

3.const迭代器

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
const迭代器只能读,不能写,适于const对象使用;其他用法和非const迭代器。

void test_string5()
{
	string s("123456");
	string::const_iterator it1 = s.begin();
	while (it1 != s.end())
	{
		cout << *it1 << " ";
		++it1;
	}
	cout << endl;
	string::const_reverse_iterator it2 = s.rbegin();
	while (it2 != s.rend())
	{
		cout << *it2 << " ";
		++it2;
	}
	cout << endl;
}

在这里插入图片描述
为此,C++11特意区别了普通迭代器和const迭代器提供了下面的接口,作为区分:
在这里插入图片描述

七、Capacity容量操作

1.接口

在这里插入图片描述

函数名称功能说明
size(重点)返回字符串有效字符长度
length返回字符串有效字符长度
capacity返回空间总大小
empty (重点)检测字符串释放为空串,是返回true,否则返回false
clear (重点)清空有效字符
reserve (重点)为字符串预留空间**
resize (重点)将有效字符的个数该成n个,多出的空间用字符c填充
void test_string6()
{
	string s("hello world!");
	cout << s.size() << endl;//12
	cout << s.length() << endl;//12
	cout << s.capacity() << endl;//15
	cout << s << endl;
	// 将s中的字符串清空,注意清空时只是将size清0,不改变底层空间的大小
	s.clear();
	cout << s.size() << endl;//0
	cout << s.capacity() << endl;//15

	// 将s中有效字符个数增加到10个,多出位置用'a'进行填充
	// “aaaaaaaaaa”
	s.resize(10, 'a');
	cout << s << endl;
	cout << s.size() << endl;//10
	cout << s.capacity() << endl;//15
	// 将s中有效字符个数增加到15个,多出位置用缺省值'\0'进行填充
	// "aaaaaaaaaa\0\0\0\0\0"
	s.resize(15);
	cout << s << endl;
	cout << s.size() << endl;//15
	cout << s.capacity() << endl;//15
	// 注意此时s中有效字符个数已经增加到15个
	s.resize(16, 'x');
	cout << s.size() << endl;//16
	cout << s.capacity() << endl;//31,超过15,扩容
	cout << s << endl;
	// 将s中有效字符个数缩小到5个
	s.resize(5);
	cout << s.size() << endl;//5
	cout << s.capacity() << endl;//15
	cout << s << endl;
}

在这里插入图片描述
size()和length()两个接口的底层是一样的,都是获得size的大小。这里推荐使用size(),方便后期的接口一致。

2.扩容

在VS2022下查看扩容:

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';
		}
	}
}

在这里插入图片描述
在g++下:
在这里插入图片描述

在这里插入图片描述
但是,扩容也会有开销,如果我们提前知道要开多少,就可以使用reserve():
在这里插入图片描述

注意:

  1. size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()。
  2. clear()只是将string中有效字符清空,不改变底层空间大小。
  3. resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。
  4. reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserver不会改变容量大小。

八、Modifiers修改操作

在这里插入图片描述

函数名称功能说明
push_back在字符串后尾插字符c
append在字符串后追加一个字符串
operator+= (重点)在字符串后追加字符串str
c_str(重点)返回C格式字符串
find + npos(重点)从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置
rfind从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置
substr在str中从pos位置开始,截取n个字符,然后将其返回
#include<iostream>
#include<string>
using namespace std;
void test_string1()
{
	string s1("hello");//用"hello"构造s1
	s1.push_back(' ');//在s1后插入一个字符' '
	s1.append("world");//在s1后追加一个字符串"world"
	s1 += 'C'; // 在s1后追加一个字符'C'
	s1 += "PP"; // 在s1后追加一个字符串"PP"
	cout << s1 << endl;
	cout << s1.c_str() << endl; // 以C语言的方式打印字符串
}
int main()
{
	test_string1();
	return 0;
}

在这里插入图片描述

#include<iostream>
#include<string>
#include<assert.h>
#include<stdio.h>
using namespace std;
void test_string1()
{
	string s1("hello world");
	//insert
	s1.insert(0, "lj ");
	cout << s1 << endl;
	s1.insert(9, "lj");
	cout << s1 << endl;
	//erasse
	s1.erase(9, 3);
	cout << s1 << endl;
	s1.erase(0, 4);
	cout << s1 << endl;
	s1.erase(5, 30);
	cout << s1 << endl;
}
void test_string2()
{
	string s1("hello world hello world");
	string s2("hello world hello world");
	string s3("we are family");
	string s4(s3);
	//assign
	s1.assign("hehehe", 5);
	cout << s1 << endl;
	//replace
	s2.replace(6, 5, "lj");
	cout << s2 << endl;

	//find与replace的结合使用
	size_t pos = s3.find(' ');
	while (pos != string::npos)
	{
		s3.replace(pos, 1, "%20");
		pos = s3.find(' ', pos + 3);
	}
	cout << s3 << endl;
	//+=的使用
	string ret;
	for (auto ch : s4)
	{
		if (ch != ' ')
		{
			ret += ch;
		}
		else
		{
			ret += "%20";
		}
	}
	cout << ret << endl;
}
//c_str
void test_string3()
{
	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);
	}
	fclose(fout);
}
int main()
{
	test_string1();
	//test_string2();
	//test_string3();
	return 0;
}

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

#include<iostream>
#include<string>
using namespace std;
void test_string1()
{
	//要求取文件名后缀
	//Test.cpp
	//Test.cpp.zip.tar
	string file;
	cin >> file;
	size_t pos = file.rfind('.');//倒着找
	if (pos != string::npos)
	{
		string sub = file.substr(pos);
		cout << sub << endl;
	}
}
int main()
{
	test_string1();
	return 0;
}

在这里插入图片描述
注意:

  1. 在string尾部追加字符时,s.push_back© / s.append(1, c) / s += 'c’三种的实现方式差不多,一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。
  2. 对string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留好。

九、非成员函数重载

在这里插入图片描述
对于流插入和流提取都是以空格、换行作为结束标志的(scanf也是)。

#include<iostream>
#include<string>
using namespace std;
void test_string1()
{
	string s1;
	cin >> s1;
	cout << s1 << endl;
	scanf("%s", &s1);
	cout << s1 << endl;
}
int main()
{
	test_string1();
	return 0;
}

在这里插入图片描述
为了解决这个问题,我们可以采用getline
在这里插入图片描述
遇到’\n’结束
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端Nodejs框架koa/egg和es6入门

故事从一个小需求开始&#xff0c;有一天我们美丽可爱的运营MM拿出来了一份Excel表格&#xff0c;希望在一些特定场景能让小蜜按照她定制的样子来交互&#xff0c;并且每一条问题或答案都带一些值来影响处理过程最终能对用户看到的结果起到一定作用。Excel里包含两个sheet页&am…

【C++类型转换】4种类型转换:static_cast、reinterpret_cast、const_cast、dynamic_cast

目录 1. C语言中的类型转换 2.1.类型转换&#xff1a;static_cast 2.2.类型转换&#xff1a;reinterpret_cast 2.3.类型转换&#xff1a;const_cast 2.4.类型转换&#xff1a;dynamic_cast 1. C语言中的类型转换 隐式类型转换&#xff1a;编译器在编译阶段自动进行&#x…

第9章 无监督学习

系列文章目录 第1章 绪论 第2章 机器学习概述 第3章 线性模型 第4章 前馈神经网络 第5章 卷积神经网络 第6章 循环神经网络 第7章 网络优化与正则化 第8章 注意力机制与外部记忆 第9章 无监督学习 第10章 模型独立的学习方式 第11章 概率图模型 第12章 深度信念网络 第13章 深…

两种形式的import

两种形式 import … 后面只能是模块或包 from … import … from 后面只能是模块或包&#xff0c;import 后面可以是任何变量 总结 可以简单的记成&#xff1a;第一个空只能填模块或包&#xff0c;第二个空填啥都行。 看一个实例 通过from import可以正常都模块 import方式不…

安装head

版本 github地址&#xff1a;https://gitcode.net/mirrors/mobz/elasticsearch-head?utm_sourcecsdn_github_accelerator 下载zip 解压zip得到文件夹elasticsearch-head-master 打开head命令行&#xff0c;依次按命令下载 下载淘宝镜像&#xff1a; npm install -g cnpm -…

程序员需知的9个编程学习官网,建议收藏

毫无疑问&#xff0c;一项技术&#xff0c;最权威的文档一定是它的官方文档&#xff0c;所有的教程、书籍都是直接或者间接在官方相关文档的基础上完成。所以&#xff0c;编程学习&#xff0c;后面最好还是要看官网的。当然&#xff0c;官网大部分都是英文——其实配合一些翻译…

Ubuntu下Petalinux安装流程与常见问题解决

一. 简介 由于近期需要对ZYNQ ARM端做Linux开发测试&#xff0c;需要用到Petalinux工具进行定制&#xff0c;所以本文对Petalinux安装过程进行简要总结&#xff0c;并对安装过程中遇到的一些问题进行解释并解决。 Petalinux是Xilinx公司开发的嵌入式Linux定制软件&#xff0c;…

「C#」异步编程玩法笔记-async、await

C#5.0的时候引入了async和await两个修饰符&#xff0c;成为异步编程的核心关键字。 async 是修饰符&#xff0c;表明方法含有异步操作&#xff0c;但并不是说整个方法是异步的。async修饰的方法会先同步执行到第一处await的地方而后开始异步。 await可以理解为一异步特有的“re…

使用Python制作内马尔的胜利之舞代码版

不知道大家最近有没有被球星内马尔所吸引&#xff0c;反正我是对他的胜利之舞上瘾了。今天&#xff0c;我以程序猿的视角将他的胜利之舞做成代码版的视频。话不多说&#xff0c;先看看最终效果图&#xff1a; 哈哈哈哈&#xff0c;是不是看着还不错的样子。 之前我做过类似的教…

小程序游戏 vs h5游戏,技术优势分别有哪些

从“跳一跳”到“羊了个羊”微信小游戏上线4年时间&#xff0c;除了涌现出不少火爆全网的小游戏之外&#xff0c;也有类似于“动物餐厅”、“口袋奇兵”等游戏得以在此孵化繁荣&#xff0c;凭借着微信强大的社交属性小游戏成为游戏厂商在桌面端、App 端、H5 端之外争夺的另一个…

微软宣布 S2C2F 已被 OpenSSF 采用

开源供应链安全对大多数 IT 领导者来说是个日益严峻的挑战&#xff0c;围绕确保开发人员在构建软件时如何使用和管理开源软件 (OSS) 依赖项的稳健策略至关重要。Microsoft 发布安全供应链消费框架 (S2C2F) 是一个以消费为中心的框架&#xff0c;它使用基于威胁的风险降低方法来…

linux下安装部署es-head插件

es通过程序代码调用es 各种api接口。 es-head查看与显示es状态信息&#xff0c;数据量&#xff0c;具体数据。 1、elasticsearch-head介绍 官方地址: https://github.com/mobz/elasticsearch-head elasticsearch-head 是一款用来管理Elasticsearch集群的第三方插件工具。 e…

用二元泊松模型预测2022年世界杯淘汰赛结果

用二元泊松模型预测2022年世界杯淘汰赛结果 网上有很多文章用双泊松&#xff08;Double Poisson&#xff09;模型来预测世界杯比赛结果。但是双泊松模型有一个严重的缺陷&#xff0c;那就是它假设比赛中两队的比分是条件独立的。而我们都知道&#xff0c;在对抗性比赛中&…

国产API管理神器Eolink也太强了吧

一、研发痛点 什么是API研发管理 API研发管理是包含了API开发管理、开发团队协作、自动化测试、网关以及监控等等API管理全生命周期的一系列管理过程。可以帮助公司实现开发运维一体化&#xff0c;提升开发速度&#xff0c;达到降本增效的目标。 前端痛点 针对前端开发在使…

Metabase学习教程:权限-2

使用集合权限 设置具有权限的集合&#xff0c;以帮助用户组织和共享与其相关的工作。 集合保持问题,仪表板&#xff0c;和模型有条理&#xff0c;容易找到。将集合视为存储我们工作的文件夹是很有帮助的。集合权限授予一群人访问&#xff1a; 查看或编辑保存在集合中的问题、…

激活企业数字化采购价值,智慧采购管理系统助力半导体行业提升采购协同效率

如今&#xff0c;随着国内经济不断发展以及国家对半导体行业的政策扶持&#xff0c;我国半导体行业发展迅速&#xff0c;半导体技术含量与日俱增的同时&#xff0c;也对我国半导体企业的管理效能与管理工具提出了更高的要求。在海外对国内半导体产业发展日益严格的当下&#xf…

Netty篇之如何优雅的关服

强制关服的危害 linux中关服如果我们使用 kill -9 pid号或者在windows中使用 taskkill /f /pid pid号来关服的话&#xff0c;相当于是突然断电的方式&#xff0c;会导致如下几种情况。 缓存中的数据丢失正在进行文件的写操作&#xff0c;没有更新完成&#xff0c;突然退出会…

技术分享 | Redis 集群架构解析

作者&#xff1a;贲绍华 爱可生研发中心工程师&#xff0c;负责项目的需求与维护工作。其他身份&#xff1a;柯基铲屎官。 本文来源&#xff1a;原创投稿 *爱可生开源社区出品&#xff0c;原创内容未经授权不得随意使用&#xff0c;转载请联系小编并注明来源。 一、集群架构的一…

决策树算法中处理噪音点

目录 如何解决&#xff1f;——采用剪枝的方法。 预剪枝 后剪枝 如果训练集中存在噪音点&#xff0c;模型在学习的过程总会将噪音与标签的关系也学习进去&#xff0c;这样就会造成模型的过拟合化&#xff0c;也就是模型在训练集的分类效果很好&#xff0c;在未知数据上处理效…

python快速实现2048小游戏

《2048》是一款比较流行的数字游戏&#xff0c;最早于2014年3月20日发行。原版2048首先在GitHub上发布&#xff0c;原作者是Gabriele Cirulli&#xff0c;后被移植到各个平台。这款游戏是基于《1024》和《小3传奇》的玩法开发而成的新型数字游戏。 操作指南&#xff1a; 每次…