C++ STL:string类的概述及常用接口说明

news2024/9/29 7:17:39

目录

一. 什么是STL

二. string类的概述

三. string类的常用接口说明

3.1 字符串对象创建相关接口(构造函数)

3.2 字符串长度和容量相关接口

3.3 字符访问相关接口函数

3.4 字符串删改相关接口函数

3.5 字符查找和子串相关接口函数

3.6 迭代器相关接口函数

3.7 常用的关于string类对象的全局函数


一. 什么是STL

STL,即标准库模板(standard template library),是C++标准库的重要组成部位,是一个包含了很多经常使用的数据结构和算法的软件框架。

C++标准规定的STL有六大组件:容器、迭代器、算法、仿函数、空间配置器和配接器,其中容器就是我们常说的数据结构。

图1.1 STL六大组件

二. string类的概述

string类,是专为用于存储和操作字符串的类,使用STL string容器的接口,可以实现对字符串进行增删查改、计算长度、循环遍历等操作。string类是模板类basic_string以char为模板参数类型的一个实例,其定义为:typedef basic_string<char> string。

那么或许会有人问:字符串的每个字符不都是char类型吗,那么直接将basic_string的参数类型定义为char不就行了吗,为什么还要定义模板再实例化?

其实,我们通常认为的char类型仅仅可以表示英文字母或字符,每个char类型数据的值,通过编码表(通常为ASCII码表)与特定字符对应,由于英文字母仅有26个,加上各种可打印字符不过128个,char类型数据完全足够对英文进行编码。

但是,其他语言就不一样了,中文汉字有几万几十万,char类型数据是无法表示的。因此,为了对汉字进行编码,就引入wchar_t型数据,一个wchar_t型数据占2byte,可以表示60000多个汉字,基本可以涵盖所有常见汉字。

因此,basic_string之所以不直接将成员变量类型设为char而是采用模板,就是为了能够实例化出不同类型的模板参数,以对应不同的编码规则,从而使其适用于全世界的语言。

常见的编码规则

编码:通过值与符号表建立映射关系,从而使值可以转换为各种字符。

  • ASCII码 -- 适用于英文。
  • unicode -- 全世界文字的通用编码表,又称万国码。它为世界各国语言的每个字符设置了统一且唯一的二进制编码。unicode下面有包括utf-8、utf-16、utf-32这几种细化的编码规则,他们分别表示以无符号的8、16、32个二进制位的数据进行编码。
  • gkb -- 为中文量身定制的编码表。

在Windows下,中文采用gkb编码规则,长字节w_char类型数据可用于中文编码。

三. string类的常用接口说明

3.1 字符串对象创建相关接口(构造函数)

  • string() -- 创建空字符串对象(仅包含字符串结束标识\0)。
  • string(const string& s) -- 拷贝构造,通过一个string类对象创建一个新的string类对象。注意string类的拷贝构造函数完成的是深拷贝,他会为新创建的对象再开辟一块内存空间,用于存储与s对象相同的字符,即:两者表示的字符串内容相同,但并不是存储在同一块空间的字符串。
  • string(const char* s) -- 通过一个现有的字符串构造string类对象。
  • string(const string& s, size_t pos, size_t len = npos) -- 通过一个string类对象的子字符串构建新的对象,子串的为:从下标pos开始为第一个字符,向后len个字符。缺省参数npos为string类的静态成员变量,值为size_t类型的-1(一个极大的数)。如果pos往后的字符数不足len,那么就用从pos往后的所有字符创建对象。
  • string(const char* s, size_t n) -- 用字符串s的前n个字符构建字符串。

演示代码3.1:

int main()
{
	string s1;   //空字符串构建
	string s2("abcdef");  //通过字符串创建对象
	string s3(s2);   //通过拷贝构造创建新对象
	string s4(s2, 1, 3);  //通过已有类对象的子串创建新对象 -- "bcd"
	string s5("abcdef", 3);   //通过字符串的前n个字符创建新对象 -- "abc"

	cout << "s1 = " << s1 << endl;
	cout << "s2 = " << s2 << endl;
	cout << "s3 = " << s3 << endl;
	cout << "s4 = " << s4 << endl;
	cout << "s5 = " << s5 << endl;

	return 0;
}
图3.1 演示代码3.1的运行结果

3.2 字符串长度和容量相关接口

  • size -- 获取字符串长度(不包括末尾\0),函数原型为:size_t size() const。
  • length -- 获取字符串长度(不包括末尾\0),函数原型为:size_t length() const。

在string类中,size和length没有任何区别。但是,size可以用在树、链表等其他数据结构中计算数据量,而length不行。为了保证STL中各种数据结构的接口名称统一,一般建议使用size。

  • capacity -- 获取当前string类对象能够存储的有效字符量,函数原型为:size_t capacity() const。
  • reserve -- 将字符串空间扩容到至少一定的值,函数原型为:void reserve(size_t n)。用reserve进行扩容,并一定恰好扩容到n,而是扩容到不小于n。同时,reserve不影响字符串中原来的内容,且不对扩大的那部分空间进行初始化,如果n小于原来的capacity,那么reverse函数不进行任何工作。
  • resize -- 使字符串的长度(size\length)变到n,函数原型为:void resize(size_t n)、void resize(size_t n, char ch),这两个函数构成重载。resize函数的工作为:将函数长度扩大到n,在将扩大的部分的内容改为ch,如果不给定ch值,则默认为'\0'。如果n小于原来的长度size,那么就截取前n个内容。
  • clear -- 清空字符串的内容,使字符串的长度(size\length)变为0。
  • empty -- 判断字符串是否为空。

演示代码3.2:

int main()
{
	string s1("abc");

	cout << "size = " << s1.size() << endl;
	cout << "length = " << s1.length() << endl;  //获取s1的长度
	cout << "capacity = " << s1.capacity() << endl;  //获取s1的容量
	cout << endl;

	s1.resize(10, 'x');
	cout << "s1 = " << s1 << endl;  //abcxxxxxxx
	cout << "size = " << s1.size() << endl;   //10
    cout << endl;

	s1.reserve(20);   //将s1的容量扩大到至少20
	cout << "capacity = " << s1.capacity() << endl;  // >=20
	cout << "size = " << s1.size() << endl;  //3
	cout << endl;

	cout << s1.empty() << endl;  //非0
	s1.clear();  //清空数据
	cout << s1.empty() << endl;  //0
	cout << "size = " << s1.size() << endl;  //0
	cout << "capacity = " << s1.capacity() << endl;  //31

	return 0;
}
图3.2  演示代码3.2的运行结果

3.3 字符访问相关接口函数

  • [] -- 下标引用操作符重载:char& operator[](size_t pos)、const char& operator[](size_t pos) const,两个函数构成重载,分别用于访问普通类对象和const类对象。
  • at -- 访问指定下标位置处的字符:char& at(size_t pos)、const char& at(size_t pos) const。

重载[]和at都可以达到访问某个下标位置处字符的目的,但是,当出现越界访问时,[]会assert断言出错,at会抛异常,且[]更符合一般的编码习惯,这里推荐使用[]而不是ar。

演示代码3.3:

int main()
{
	string s1("abcdef");
	const string s2("abcdef");

	//使用[],将s1的每个值+1
	for (size_t i = 0; i < s1.size(); ++i)
	{
		s1[i] += 1;
	}
	cout << s1 << endl;  //bcdefg

	//[]访问const对象s2的每个字符,只能读不能写
	for (size_t i = 0; i < s2.size(); ++i)
	{
		//s2[i] += 1;  //报错
		cout << s2[i];
	}
	cout << endl;

	//通过at函数,遍历打印s2的每个字符
	for (size_t i = 0; i < s2.size(); ++i)
	{
		cout << s2.at(i);
	}
	cout << endl;

	return 0;
}
图3.3 演示代码3.3

3.4 字符串删改相关接口函数

  • operator+= -- 尾插字符或字符串
  1. string& operator+=(const string& s)  -- 通过类对象获取尾插字符串
  2. string& operator+=(const char* s) -- 直接尾插字符串s
  3. string& operator+=(char c) -- 尾插字符c
  • push_back -- 尾插字符。函数原型为:void push_back(char c)
  • append -- 尾插字符串或字符
  1. string& append(const string& s) -- 通过string类对象获取字符串尾插
  2. string& append(const char* s) -- 直接尾插字符串
  3. string& append(const string& s, size_t pos, size_t len = npos) -- 通过获取子字符串尾插
  4. string& append(const char* s, size_t n) -- 尾插字符串s的前n个字符
  • insert -- 在指定位置插入字符或字符串
  1. string& insert(size_t pos, const string& s) -- 在pos下标处通过string类对象插入字符串
  2. string& insert(size_t pos, const string& s, size_t subpos, size_t len = npos) -- 在pos位置处插入string对象的一个子字符串
  3. string& insert(size_t pos, const char* s) -- 在pos下标处插入字符串s
  4. string& insert(size_t pos, const char* s, size_t n) -- 在pos下标处插入s的前n个字符
  5. string& insert(size_t pos, size_t n, char c) -- 在pos位置处插入n个c字符
  • erase -- 从指定位置开始删除n个字符,函数原型:string& erase(size_t pos = 0, size_t len = npos)

演示代码3.4:

int main()
{
	string s1;

	s1 += "aaa";  //+=尾插字符串
	cout << s1 << endl;
	s1 += 'b';  //+=尾插单个字符
	cout << s1 << endl;
	s1.push_back('c');  //push_back尾插单个字符
	cout << s1 << endl;
	s1.append("ddd");  //append尾插字符串
	cout << s1 << endl;
	cout << endl;

	string s2("aaaaaaa");

	s2.insert(2, "bbbb");  //在下标2的位置插入字符串"bbbb"
	cout << s2 << endl;
	s2.erase(2, 4);   //从下标为2的位置开始删除4个字符
	cout << s2 << endl;

	return 0;
}
图3.4 演示代码3.4的运行结果

3.5 字符查找和子串相关接口函数

  • c_str -- 获取string类对象中的字符串成员(字符串首字符地址)。函数原型为:const char* c_str() const。
  • find -- 以指定下标位置pos为起点,从前向后查找特定字符或子字符串,找到了返回字符或子串第一次出现的下标,找不到就返回npos。
  1. size_t find(const string& s, size_t pos = 0) const -- 查找sting对象s的字符串。
  2. size_t find(const char* s, size_t pos = 0) const -- 查找字符串s。
  3. size_t find(const char* s, size_t pos, size_t len) const -- 查找字符串s的一个子串。
  4. size_t find(char c, size_t pos = 0) const -- 查找字符c。
  • refind -- 与find类似,从尾部开始,查找子字符串或字符第一次出现的下标位置。
  • substr -- string substr(size_t pos = 0, size_t len = npos) -- 从当前string对象中获取子串,构建一个新的string对象。

演示代码3.5:

int main()
{
	string s1("abcdefgh");

	cout << s1.c_str() << endl;  //获取字符串成员
	cout << s1.find("bcd") << endl;   //查找子串"bcd" -- 输出1
	cout << s1.find("cdeg", 2, 3) << endl;   //从下标2处开始查找"cdef"前3个字符构成的子串"cde" -- 输出2
	cout << s1.find('e') << endl;  //查找字符e -- 输出4
	cout << endl;

	string s2("abcdefabcdef");
	cout << s2.rfind("abc", 9) << endl;  //查找下标位置9之前pos最后一次出现的位置 -- 输出6
	cout << s2.rfind('e') << endl;  //查找字符'e'最后一次出现的位置 -- 输出10

	string s3("abcdef");
	string s4 = s3.substr(1, 4);
	cout << "s4 = " << s4 << endl;   //bcde
	  
	return 0;
}
图3.5 演示代码3.5运行结果

3.6 迭代器相关接口函数

迭代器的类型为iterator,是char*的类型重定义名称,其定义语句为:typedef char* iterator -- 对于普通对象的迭代器,typedef const char* const_iterator -- 对于const属性对象的迭代器。除了一般的iterator以外,还有反向迭代器reverse_iterator和const_reverse_iterator。

对iterator类型的变量执行++操作,其指向的位置后移一位、对reverse_iterator类型的成员变量执行++操作,其指向的位置前移一位。

  • begin -- 获取指向字符串首元素的指针,函数原型为:iterator begin()和const_iterator begin() const,这两个函数构成重载,分别应用于普通对象和const属性对象。
  • end -- 获取指向字符串最后一个元素后面那个位置('\0')的指针,函数原型为:iterator end()和const_iterator end() const。
图3.6 begin和end函数返回值的指向位置示意图
  • rbegin -- 返回指向字符串最后一个字符的指针,函数原型为:reverse_iterator rbegin() 和 const_reverse_iterator rbegin() const。
  • rend -- 返回指向字符串第一个字符前一个位置的指针,函数原型为:reverse_iterator rend() 和 const_reverse_iterator rend() const。
图3.7 rbegin和rend返回值指向的位置示意图

演示代码3.6:

int main()
{
	string s1("abcde");
	//使用正向迭代器遍历s1的每个字符,+1后输出
	string::iterator it1 = s1.begin();
	while (it1 != s1.end())
	{
		++(*it1);
		cout << *it1;  //输出bcdef
		++it1;
	}
	cout << endl;

	string s2("abcde");

	//使用反向迭代器,反向遍历s2的每个字符并输出
	string::reverse_iterator it2 = s2.rbegin();
	while (it2 != s2.rend())
	{
		cout << *it2;  //输出edcba
		++it2;
	}
	cout << endl;

	return 0;
}
图3.8  演示代码3,6的运行结果  

3.7 常用的关于string类对象的全局函数

在C语言阶段,学过函数atoi,功能是将字符串转化为整数。但是,C/C++标准库函数中并没有atoi函数,虽然大部分编译器都已支持atoi函数,但是,依然建议不要使用,这样会降低程序的可移植性,很多老式编译器依然不支持atoi。

  • stoi -- 将string类对象转换为int型数据。
  • stol -- 将string类对象转换为long int型数据。
  • stoul -- 将string类对象转换为unsigned long int型数据。
  • stoll -- 将string类对象转换为long ong型数据。
  • stoull -- 将string类对象转换为转换为unsigned long long型数据。
  • stof -- 将string类对象转换为float型数据。
  • stod -- 将string类对象转换为double型数据。

上述函数,会自动排除字符串前部的空格,会通过'+'、'-'字符判断返回值的正负,当遇到非数字字符时,函数会终止执行,返回当前值。

注意:如果string无法转换为数字(首个非空字符不是'+'、'-'或数字字符),以及超出数据类型表示范围的情况下,上述函数均会抛异常,引发程序崩溃。

演示代码3.7:

int main()
{
	string s1(" -123ab1");
	string s2(" 1234");
	string s3("+1234abc");
	string s4("aa");

	string s5("-123.12");
	string s6("100.111abc");
	string s7("110.ab");
	string s8("001234.5");

	string s9("123456789987654321");

	cout << "s1 = " << stoi(s1) << endl;  //-123
	cout << "s2 = " << stoi(s2) << endl;  //1234
	cout << "s3 = " << stoi(s3) << endl;  //1234
	//cout << "s4 = " << stoi(s4) << endl;  //无法转换为int会抛异常

	cout << "s5 = " << stod(s5) << endl;  //-123.12
	cout << "s6 = " << stod(s6) << endl;  //110.111
	cout << "s7 = " << stod(s7) << endl;  //110
	cout << "s8 = " << stod(s8) << endl;  //1234.5

	//cout << "s9 = " << stoi(s9) << endl;  //超出int范围会抛异常

	return 0;
}

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

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

相关文章

c++11右值引发的概念

右值引用右值&&左值c11增加了一个新的类型&#xff0c;右值引用&#xff0c;记作&#xff1a;&&左值是指在内存中有明确的地址&#xff0c;我们可以找到这块地址的数据&#xff08;可取地址&#xff09;右值是只提供数据&#xff0c;无法找到地址&#xff08;不…

跨时钟域CDC

https://www.cnblogs.com/icparadigm/p/12794483.html https://www.cnblogs.com/icparadigm/p/12794422.html 亚稳态 是什么 时序逻辑在跳变时&#xff0c;由于异步信号、跨时钟域等原因&#xff0c;不满足setup或hold条件&#xff0c;输出在0和1之间产生振荡。 原因 D触发…

Canny算法原理和应用

Canny算法的原理使用高斯滤波器滤波使用 Sobel 滤波器滤波获得在 x 和 y 方向上的输出&#xff0c;在此基础上求出梯度的强度和梯度的角度edge为边缘强度&#xff0c;tan为梯度方向上图表示的是中心点的梯度向量、方位角以及边缘方向&#xff08;任一点的边缘与梯度向量正交&am…

如何在MySQL 8中实现数据迁移?这里有一个简单易用的方案

文章目录前言一. 致敬IT领域的那些女性二. 进制方式安装MySQL2.1 下载软件包2.2 配置环境&#xff1a;2.2.1 配置yum环境2.2.2 配置安全前的系统环境2.3 开始安装2.4 初始化MySQL2.5 修改配置文件2.6 将MySQL设为服务并启动测试三. MySQL数据迁移总结前言 正好赶上IT女神节&am…

《Linux运维实战:ansible中的变量定义及以及变量的优先级》

一、配置文件优先级 Ansible配置以ini格式存储配置数据&#xff0c;在Ansible中⼏乎所有配置都可以通过Ansible的Playbook或环境变量来重新赋值。在运⾏Ansible命令时&#xff0c;命令将会按照以下顺序查找配置⽂件。 # ⾸先&#xff0c;Ansible命令会检查环境变量&#xff0c…

【node : 无法将“node”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。 最全面有效的解决方案】

执行nodejs文件错误&#xff1a; 这个错误提示通常是由于你的系统无法识别 "node" 命令&#xff0c;可能是由于你没有正确地安装或配置 Node.js 环境变量。 问题描述 ​​​​​​​​​​​​​​ 原因分析&#xff1a; 可能原因包括&#xff1a; 1.Node.js未正确安…

JVM堆与堆调优以及出现OOM如何排查

调优的位置——堆 Heap&#xff0c;一个JVM只有一个堆内存&#xff0c;堆内存的大小是可以调节的。 类加载器读取了类文件后&#xff0c;一般会把什么东西放到堆中?类&#xff0c;方法&#xff0c;常量&#xff0c;变量~&#xff0c;保存我们所有引用类型的真实对象; 堆内存中…

【Linux修炼】15.进程间通信

每一个不曾起舞的日子&#xff0c;都是对生命的辜负。 进程间通信进程间通信一.理解进程间通信1.1 什么是通信1.2 为什么要有通信1.3 如何进行进程间通信二.管道2.1 匿名管道2.2 匿名管道编码部分2.3 管道的特点2.4 如何理解命令行中的管道2.5 进程控制多个子进程三.命名管道3.…

openEuler用户软件仓(EUR)介绍

什么是 EUR EUR(openEuler User Repo)是openEuler社区针对开发者推出的个人软件包托管平台&#xff0c;目的在于为开发者提供一个易用的软件包分发平台。 链接&#xff1a;https://eur.openeuler.openatom.cn/ 为什么我们需要 EUR 在操作系统的世界&#xff0c;软件包是一等…

数据库基本功之复杂查询-多表连接

1. 简单查询的解析方法 全表扫描:指针从第一条记录开始,依次逐行处理,直到最后一条记录结束;横向选择纵向投影结果集 2. 多表连接 交叉连接(笛卡尔积) 非等值连接 等值连接 内连 外连接(内连的扩展,左外,右外,全连接) 自连接 自然连接(内连,隐含连接条件,自动匹配连接字段) …

以创作之名致敬女性开发者

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 前言 在昨天的2023年3月8日&#xff0c;是咱们女性朋友的节日妇女节&#xff0c;本章将会…

腾讯云GPU游戏服务器/云主机租用配置价格表

用于游戏业务的服务器和普通云服务器和主机空间是不同的&#xff0c;游戏服务器对于硬件的配置、网络带宽有更大的要求&#xff0c;一般游戏服务器根据不同的配置和适用场景会有十几元一小时到几十元一小时&#xff0c;而且可以根据不同的按量计费。而普通的云服务器可能需要几…

Linux程序替换

Linux程序替换创建子进程的目的&#xff1f;程序替换如何实现程序替换&#xff1f;什么是程序替换&#xff1f;先见一见单进程版本的程序替换程序替换原理多进程版本的程序替换execl函数组简易版Shell创建子进程的目的&#xff1f; 目的:为了帮助父进程完成一些特定的任务&…

网络实时变更监控

网络变更监控 未经授权的配置变更会严重破坏业务连续性&#xff0c;这就是为什么检测和跟踪变更是网络管理员的一项关键任务。虽然可以手动跟踪变更&#xff0c;但此方法往往很耗时&#xff0c;并且经常会导致人为错误&#xff0c;例如在跟踪时遗漏了关键网络设备的配置。 要解…

JavaEE简单示例——Spring的控制反转

简单介绍&#xff1a; 在之前的入门程序中&#xff0c;我们简单的介绍了关于Spring框架中的控制反转的概念&#xff0c;这次我们就来详细的介绍和体验一下Spring中的控制反转的理论和实操。 使用方法&#xff1a; 控制反转&#xff08;IoC&#xff09;是面向对象编程中的一个…

HTML5 和 CSS3 的新特性

目标能够说出 3~5 个 HTML5 新增布局和表单标签能够说出 CSS3 的新增特性有哪些HTML5新特性概述HTML5 的新增特性主要是针对于以前的不足&#xff0c;增加了一些新的标签、新的表单和新的表单属性等。 这些新特性都有兼容性问题&#xff0c;基本是 IE9 以上版本的浏览器才支持&…

CentOS 部署rocketmq集群

一、rocketmq 概览 1.rocketmq简介 rocketmq是一个队列模型的消息中间件&#xff0c;具有高性能、高可靠、高实时、分布式特点。能够保证严格的消息顺序&#xff0c;提供丰富的消息拉取模式&#xff0c;高效的订阅者水平扩展能力&#xff0c;实时的消息订阅机制。 2.rocketmq结…

项目四:使用路由交换机构建园区网-任务三:配置路由交换机并进行通信测试

配置路由交换机并通信测试1、在RS-1上创建VLAN并配置Trunk接口2、测试通信结果3、配置RS-1的三层路由接口&#xff08;SVI&#xff09;1、在RS-1上创建VLAN并配置Trunk接口 进入系统视图&#xff0c;关闭信息中心&#xff0c;重命名为RS-1 system-view undo info-center enab…

day48第九章动态规划(二刷)

今日任务 198.打家劫舍213.打家劫舍II337.打家劫舍III 今天就是打家劫舍的一天&#xff0c;这个系列不算难&#xff0c;大家可以一口气拿下。 198.打家劫舍 题目链接&#xff1a; https://leetcode.cn/problems/house-robber/description/ 题目描述&#xff1a; 你是一个…

synchronized轻量级锁优化

synchronized优化轻量级锁 使用场景 如果一个对象虽然有多个线程访问&#xff0c;但多线程访问时间是错开的&#xff0c;也就是没有竞争&#xff0c;那么可以使用轻量级锁优化&#xff1b; 原理 1、每个线程的栈帧中有锁记录 包括&#xff1a;记录锁对象的地址Object refer…