探索c++:string常用接口 迷雾

 

 个人主页:日刷百题

系列专栏〖C/C++小游戏〗〖Linux〗〖数据结构〗 〖C语言〗

🌎欢迎各位点赞👍+收藏⭐️+留言📝 

一、string

这里我们对string类进行一个简单的总结:

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

这里有一个需要注意的点:
在使用string类时,必须包含#include头文件以及using namespace std;

二、string类的常用接口

2.1  string对象常见构造(constructor)

(constructor)函数名称   功能说明
string()(重点)  构造空的string类对象,即空字符串
string(const char* s)(重点)用C-string来构造string类对象
string(size_t n, char c) string类对象中包含n个字符
string(const string&s)(重点) 拷贝构造函数
2.1.1  string()
  • 构造空的string对象,即空字符串
//空构造函数
#include<iostream>
using namespace std;
int main()
{
	string s1;
	cout << s1 << endl;
	return 0;
}
 2.1.2  string(const char* s)
  • 用C-string来构造string类对象
//常量字符串                                           
#include<iostream>
using namespace std;
int main()
{
	string s1("hello world");
	cout << s1 << endl;
	return 0;
}

 其实相当于将常量字符串拷贝到str中

 2.1.3  string(size_t n, char c)
  • 用n个相同的字符c去构造string类对象
//创建一个包含 5 个重复字符 'a' 的字符串
#include<iostream>
using namespace std;
int main()
{
	string s1(5,'a');
	cout << s1 << endl;
	return 0;
}

 2.1.4  string(const string&s) 
  • 拷贝构造(深拷贝),只有调用默认拷贝构造才是浅拷贝
#include<iostream>
using namespace std;
int main()
{
	string s1("hello world");
	cout << s1 << endl;
	string s2(s1);
	cout << s1 << endl;
    cout << s2 << endl;
    cout << &s1 << endl;
    cout << &s2 << endl;
	return 0;
}

2.1.5 string (const string& str, size_t pos, size_t len = npos)

  • 拷贝一个string类对象,读取从他的第pos个位置开始的往后的len个字符
#include<iostream>
using namespace std;
int main()
{
	string s1("hello world");
	cout << s1 << endl;
	string s2(s1, 6, 3);
	cout << s2 << endl;
	return 0;
}

注:

如果拷贝的字符数量大于字符串的字符个数的话,就全部打印完;如果不给值,则是缺省值npos,值为-1,也是全部打完。

 2.2  string类对象的容量操作(Capacity)

函数名称    功能说明
size(重点)返回字符串有效字符长度
length  返回字符串有效字符长度
capacity 返回空间总大小
empty (重点)检测字符串释放为空串,是返回true,否则返回false
clear (重点) 清空有效字符
reserve (重点) 为字符串预留空间**
resize (重点)将有效字符的个数该成n个,多出的空间用字符c填充
2.2.1  size和length

  • size和length其实是一样的, 都代表字符串的长度,但是早期STL还没出现的时候,strling类用的是length,但是后来STL出来后,里面大部分都是用的size,所以为了保持一致性又造了一个size出来,平时用哪个都可以的。

用法如下:

#include<iostream>
using namespace std;
int main()
{
	string s1("hello world");
	cout << s1.length() << endl;
	cout << s1.size() << endl;
	return 0;
}

注意:这里计算出来的是有效字符个数,也就是说不包括’\0’

2.2.2  capacity

  • 表示string当前的容量,一般来说是默认不算上’\0'

用法如下:

#include<iostream>
using namespace std;
int main()
{
	string s1("hello world");
	cout << s1.capacity() << endl;
	return 0;
}

注:vs用的是PJ版STL,字符串会先被存在_Bx数组中,是char[16]类型,超过之后才会去动态开辟空间,第一次开辟空间是32,然后从32开始进行1.5倍扩容。而g++是SGI版STL,直接就是从0开始,然后根据情况直接开始扩容,从0开始进行2倍扩容。

2.2.3  empty

  • 字符串为空返回1,不为空返回0

用法如下:

#include<iostream>
using namespace std;
int main()
{
	string s1("hello world");
	cout << s1.empty() << endl;
	return 0;
}

2.2.4  clear

  • 清空字符串
#include<iostream>
using namespace std;
int main()
{
	string s1("hello world");
	cout << s1 << endl;
	s1.clear();
	cout << s1 << endl;
	return 0;
}

2.2.5  reverse

  • 作用是开空间,扩容
  1. 如果 n 大于当前字符串容量(capacity),则该函数会导致容器将其容量增加到 n 个字符(或更大)。 
  2. 在所有其他情况下,它被视为一个非约束性的缩减字符串容量请求:容器实现可以自由优化,保持字符串的容量大于n。
  3. 此函数对字符串长度没有影响,也无法更改其内容。(当n小于对象当前的capacity时,什么也不做)
#include<iostream>
using namespace std;
int main()
{
	string s1("hello world");
	cout << s1.capacity() << endl;
	cout << s1.size() << endl;
    //1.5倍扩容
	s1.reserve(30);
	cout << s1.capacity() << endl;
	cout << s1.size() << endl;
	return 0;
}

  • 扩容不会改变size()。 
  • vs根据1.5倍的扩容规则,至少会扩容到超过你的要求。如果是g++的话,就是2被扩容。
2.2.6  resize 

  • 改变size,减少的话就是变少(不会改变容量),如果增多的话就可能会扩容顺便帮助我们初始化,第一个版本的话初始化补\0,第二个版本的话就是初始化c字符
#include<iostream>
using namespace std;
int main()
{
	string s1("hello world");
	cout << s1.capacity() << endl;
	cout << s1.size() << endl;
	s1.resize(30);
	cout << s1.capacity() << endl;
	cout << s1.size() << endl;
	return 0;
}

总结:

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

2.3 string类对象的访问及遍历操作(Iterators

函数名称功能说明
operator[] (重点)
返回 pos 位置的字符, const string 类对象调用
begin + end
begin 获取一个字符的迭代器 + end 获取最后一个字符下一个位置的迭 代器
rbegin + rend
begin 获取一个字符的迭代器 + end 获取最后一个字符下一个位置的迭 代器
范围 for
C++11 支持更简洁的范围 for 的新遍历方式

2.3.1   operater[ ]  和 at()
  • 返回该位置的字符

#include<iostream>
using namespace std;
int main()
{
	string const s1("hello world");
	for (int i = 0; i < s1.length(); i++)
	{
		cout << s1[i];
	}
	cout << endl;
	return 0;
}

注:用[ ]越界是断言错误。

#include<iostream>
using namespace std;
int main()
{
	string const s1("hello world");
	for (int i = 0; i < s1.length(); i++)
	{
		cout << s1.at(i);
	}
	cout << endl;
	return 0;
}

注:at()越界时候报的是非法。

2.3.2 迭代器(iterator)遍历

迭代器有两种,还有一个叫做反向迭代器,就是从尾部开始遍历,我们这里介绍正向迭代器
iterator是一个类型定义在string里面,所以它要指定类域,才能取到。
begin是开始的指针,end是指向‘\0’的指针,注意是左闭右开!! 

#include<iostream>
using namespace std;
int main()
{
	string s1("hello world");
	for (string::iterator i = s1.begin(); i != s1.end(); i++)
	{
		cout << *i;
	}
  cout<<endl;
	return 0;
}

反向迭代器就是从后开始往前移动:
这里要引出的是 reverse_iterator 其实这里的rbegin是字符串的最后一个位置(不是\0),并且这里的指针也是++,向前移动。

#include<iostream>
using namespace std;
int main()
{
	string s1("hello world");
	for (string::reverse_iterator i = s1.rbegin(); i != s1.rend(); i++)
	{
		cout << *i;
	}
    cout<<endl;
	return 0;
}

注:迭代器像指针,但不是指针。

2.3.3  范围for
  • 自动取容器中的数据,赋值给e,自动迭代,自动往后走,自动结束。
#include<iostream>
using namespace std;
int main()
{
	string s1("hello world");
	for (auto e:s1)
	{
		cout << e;
	}
    cout<<endl;
	return 0;
}

注:for循环的底层实现就是迭代器!

2.4 string类对象的修改操作(Modifiers)

2.4.1  push_back
  • 在字符串尾插字符C
#include<iostream>
using namespace std;
int main()
{
	string s1("hello world");
	s1.push_back('!');
	cout << s1 << endl;
	return 0;
}

2.4.2  append
  • append尾插,可以插入字符串
#include<iostream>
using namespace std;
int main()
{
	string s1("hello world");
	s1.append(" hhhh!");
	cout << s1 << endl;
	return 0;
}

2.2.3 operator+=
  • operator+=可以实现在字符串后面追加字符或者字符串,并且函数的可读性更高,所以我们一般选择使用+=来实现对对象的追加
#include<iostream>
using namespace std;
int main()
{
	string s1("hello world");
	s1+=(" hhhh!");
	cout << s1 << endl;
	s1 += ('x');
	cout << s1 << endl;
	return 0;
}

2.2.4  assign(了解即可)
  • assign赋值,字符覆盖
void test_string9() {
	// 创建一个初始内容为"xxxxxxx"的字符串str
	string str("xxxxxxx");
 
	// 创建一个基础字符串base,
	string base = "The quick brown fox jumps over a lazy dog.";
 
	// 使用assign方法将base的全部内容赋给str,替换str原来的内容
	str.assign(base);
	// 输出赋值后str的内容
	cout << str << '\n';
 
	// 第二种用法:使用assign方法从base的第5个字符开始截取10个字符,并将这10个字符赋给str
	str.assign(base, 5, 10);
	// 输出截取并赋值后str的内容
	cout << str << '\n';
}

2.2.5   insert
  • insert都是在当前位置的前面插入
#include<iostream>
using namespace std;
int main()
{
	string s1("hello world");
	cout << s1 << endl;

	s1.insert(0, "abc");
	cout << s1 << endl;
	return 0;
}

2.2.6  erase

  • erase删除:表示第pos个位置开始后len个字符删除,len的默认值是npos
#include<iostream>
using namespace std;
int main()
{
	string s1("hello world");
	cout << s1 << endl;

	s1.erase(5, 2);
	cout << s1 << endl;

	return 0;
}

2.2.7  replace

  • replace替换:将pos位置开始的len个字符替换成字符串
#include<iostream>
using namespace std;
int main()
{
	string s1("hello world");
	cout << s1 << endl;
	s1.replace(6, 1, "xx");
	cout << s1<< endl;
	return 0;
}

2.2.8  swap
  • 交换2个string类对象的指针指向
void test_string9()
{
    string s2("hello world hello abcd");
	string s3;
	s3.reserve(s2.size());
	for (auto ch : s2)
	{
		if (ch != ' ')
		{
			s3 += ch;
		}
		else
		{
			s3 += "20%";
		}
	}
	cout << s3 << endl;
	s2.swap(s3);
	cout << s2 << endl;
}

总结:

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

2.5 string类对象的操作(operations)

c_str(重点)
返回c格式的字符串
find 
从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置
rfind
从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置
substr
str中从pos位置开始,截取n个字符,然后将其返回
2.5.1  c_str
  • 以C语言的方式打印字符串
#include<iostream>
using namespace std;
int main()
{
	string s1("hello world");
	cout << s1.c_str() << endl;
	return 0;
}

注:不能通果c_str 返回的指针去修改字符串,因为它指向的是常量区域。

2.5.2  find
  • find从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置,如果没有找到会返回npos
#include<iostream>
using namespace std;
int main()
{
	string s1("file.cpp");
	size_t pos1 = s1.find('.');
	if (pos1 != string::npos)
	{
		string suffix = s1.substr(pos1);
		cout << suffix << endl;
	}
	else
	{
		cout << "没找到后缀" << endl;
	}
	return 0;
}

 

2.5.3  refind
  • rfind从字符串pos位置开始向前找字符c,返回该字符在字符串中的位置,如果没有找到会返回npos
#include<iostream>
using namespace std;
int main()
{
	    string s1("file.cpp.tar.zip");
		size_t pos1 = s1.rfind('.');
		if (pos1 != string::npos)
		{
			string suffix = s1.substr(pos1);
			cout << suffix << endl;
		}
		else
		{
			cout << "没有后缀" << endl;
		}
	

	return 0;
}

 

2.5.4  substr
  • str中从pos位置开始,截取n个字符,然后将其返回
#include<iostream>
using namespace std;
int main()
{
	string s1("hello world");
	cout << s1.substr(3, 4) << endl;
	cout << s1.substr(3, 12) << endl;
}

如何利用上面接口,区分开网站的协议,域名,网址呢?

void test_string10()
{
    string url1("https://legacy.cplusplus.com/reference/string/string/substr/");
	string protocol, domain, uri;//协议,域名,网址
	size_t i1 = url1.find(':');
	if (i1 != string::npos)
	{
		protocol = url1.substr(0, i1 - 0);
		cout << protocol << endl;
	}

	size_t i2 = url1.find('/',i1+3);
	if (i2 != string::npos)
	{
		domain = url1.substr(i1+3, i2-(i1+3));
		cout << domain << endl;

		uri = url1.substr(i2+1);
		cout << uri << endl;
	}
}

2.6  string类非成员函数

其实这里用的不多,不做过多的讲解
但是这个getline函数是可以用到一些题目中来读取字符串的,他遇到换行符就会停止读取,遇到空格不会.

 2.6.1  getline

获得一个字符串(hello word!)里面最后一个单词的长度

#include<iostream>
#include<string>
using namespace std;
int main()
{
	string line;
	// 不要使用cin>>line,因为会它遇到空格就结束了
	// while(cin>>line)
	while (getline(cin, line))
	{
		size_t pos = line.rfind(' ');
		cout << line.size() - (pos+1) << endl;
	}
	return 0;
}

 

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

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

相关文章

【更新】在湘源7、8中使用2023年11月国空用地用海分类

之前为了做控规&#xff0c;从湘源8中扒了一套国空用地用海的绘图参数给湘源7使用。 【预告】在湘源控规7中使用 国空用地用海分类标准 但是部里在2023年11月又发布了一套新的用地用海分类。 本想去湘源8里面再扒一下&#xff0c;结果发现湘源8自己还没有更新呢&#xff0c;…

使用STM32 MCU模拟实现PPS+TOD授时信号

简介 PPSTOD是授时信号的一种&#xff0c;用来传递准确的时间信息。 PPS&#xff0c;Pulse Per Second&#xff0c;是每秒一次的脉冲信号&#xff0c;其上升沿表示整秒的时刻。TOD&#xff0c;Time of Day&#xff0c;是时间信息。是跟随在每个PPS信号后的由串口发出的一句报…

Servlet Response的常用方法 缓存和乱码处理

前言 Servlet Response相关的信息&#xff0c;在service方法中使用的是HttpServletResponse&#xff0c;它继承自ServletResponse&#xff0c;扩展了Http协议相关的内容&#xff0c;下面简单记录一下它的基本用法。 一、response组成内容 以下是一个常见response响应的内容&…

红黑树介绍及插入操作的实现

&#x1f389;个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名乐于分享在学习道路上收获的大二在校生 &#x1f648;个人主页&#x1f389;&#xff1a;GOTXX &#x1f43c;个人WeChat&#xff1a;ILXOXVJE &#x1f43c;本文由GOTXX原创&#xff0c;首发CSDN&…

node.js的错误处理

当我打开一个不存在的文件时&#xff0c;错误如下&#xff1a; 在读取文件里面写入console.log&#xff08;err&#xff09;&#xff0c;在控制台中可以看到我的错误代码类型&#xff1a;文件不存在的错误代码 ENOENT。见更多错误代码---打开node.js官方API文档Error 错误 | N…

高炉项目中DeviceNET到Ethernet的转换奥秘

在工业自动化的世界中&#xff0c;高炉项目中的数据通信至关重要。其中DeviceNET和Ethernet作为两种主流的网络协议&#xff0c;扮演着不可或缺的角色。它们之间的转换不仅仅是技术上的桥梁&#xff0c;更是实现信息高效传递的关键。今天&#xff0c;我们就来揭开从DeviceNET到…

每日面经分享(pytest入门)

1. pytest具有什么功能 a. 自动发现和执行测试用例&#xff1a;pytest可以自动发现项目中的测试文件和测试函数&#xff0c;无需手动编写测试套件或测试运行器。 b. 丰富的断言函数&#xff1a;pytest提供了丰富的断言函数&#xff0c;方便地验证测试结果是否符合预期。断言函…

【STM32 HAL库SPI/QSPI协议学习,基于外部Flash读取】

1、SPI协议 简介 SPI 协议是由摩托罗拉公司提出的通讯协议 (Serial Peripheral Interface)&#xff0c;即串行外围设备接口&#xff0c;是一种高速全双工的通信总线。它被广泛地使用在 ADC、LCD 等设备与 MCU 间&#xff0c;要求通讯速率较高的场合。 通信方式&#xff1a;同…

基于SpringBoot+Vue交通管理在线服务系统的开发(源码+部署说明+演示视频+源码介绍+lw)

您好&#xff0c;我是码农飞哥&#xff08;wei158556&#xff09;&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。&#x1f4aa;&#x1f3fb; 1. Python基础专栏&#xff0c;基础知识一网打尽&#xff0c;9.9元买不了吃亏&#xff0c;买不了上当。 Python从入门到精通…

Docker搭建LNMP环境实战(10):大结局!脚本化一次性安装测试、生产环境

实现使用 Docker 在一台服务器上搭建支持 80、443 端口访问的测试、生产双站点系统。 1、生产环境&测试环境的规划和部署 1.1、说明 图1 系统部署示意图 1&#xff09;项目 此处以一个演示项目的形式来进行环境的规划和部署。此项目名称默认定义为&#xff1a;“demo”&a…

网安学习笔记-day11,FTP服务器

FTP服务器 FTP介绍 FTP(File Transfer Protocol)文件传输协议 端口号&#xff1a;TCP 20/21 工作方式&#xff1a; 主动模式被动模式 服务器部署 准备阶段 配置IP windowsXP 192.168.1.21&#xff08;也可DHCP自动获取&#xff09; Windows2003 192.168.1.1 安装万维网…

[SWPUCTF 2021 新生赛]crypto5(小明文攻击)

题目&#xff1a; 直接暴力破解&#xff1a; from Cryptodome.Util.number import * import gmpy2 flag 251667516535309413648396638468065433877208653392633709079856557751521873194647157371165991714772070474300653458826262598807568390941796270326238953302426553…

Mybatis-Plus分页查询时碰到`total`有值但`records`为空

个人原因&#xff1a;Mybatis-Plus分页插件设置了maxLimit单页条数 // 分页插件配置 PaginationInnerInterceptor paginationInnerInterceptor new PaginationInnerInterceptor(DbType.MYSQL); paginationInnerInterceptor.setMaxLimit(200L); // 单页分页条数限制(默认无限…

Mysql重点思考(上)--mysql的索引优化

mysql的索引优化 expalin关键字的用法explain索引优化示例 type列用法执行查询的顺序类型概述 索引概念索引的定义索引的分类主键&唯一区别 唯一索引的创建和查询创建一个唯一索引查询一个唯一索引 场景题合集唯一索引的场景题主键索引的场景题&#xff08;B树&#xff09;…

Python下载bing每日壁纸并实现win11 壁纸自动切换

前言: 爬虫哪家强,当然是python 我是属于啥语言都用,都懂点,不精通,实际工作中能能够顶上就可以。去年写的抓取bing每日的壁纸&#xff0c;保存到本地&#xff0c;并上传到阿里云oss&#xff0c;如果只是本地壁纸切换&#xff0c;存下来就行&#xff0c;一直想做个壁纸站点&…

第四篇:3.3 无效流量(Invalid traffic) - IAB/MRC及《增强现实广告效果测量指南1.0》

翻译计划 第一篇概述—IAB与MRC及《增强现实广告效果测量指南》之目录、适用范围及术语第二篇广告效果测量定义和其他矩阵之- 3.1 广告印象&#xff08;AD Impression&#xff09;第三篇广告效果测量定义和其他矩阵之- 3.2 可见性 &#xff08;Viewability&#xff09;第四篇广…

火力发电必备:DeviceNET转Modbus TCP神技

在当今工业自动化领域&#xff0c;设备间的信息交流至关重要&#xff0c;其中Modbus协议由于其简单、开放和易于实施的特性&#xff0c;已经成为了事实上的行业标准。然而&#xff0c;随着技术的发展&#xff0c;对实时性、可靠性和数据传输速度的要求越来越高&#xff0c;尤其…

【C++航海王:追寻罗杰的编程之路】priority_queue(优先队列) | 容器适配器你知道哪些?

目录 1 -> priority_queue的介绍和使用 1.1 -> priority_queue的介绍 1.2 -> priority_queue的使用 1.3 -> priority_queue的模拟实现 2 -> 容器适配器 2.1 -> 什么是适配器 2.2 -> STL标准库中stack和queue的底层结构 2.3 -> deque的介绍 2.…

Error: Cannot find module ‘@rollup/rollup-win32-x64-msvc‘

1.背景 新项目需要使用vite搭建一个v3项目,之前也弄过,但项目创建后却一直无法跑起来,大聪明的我一直没有注意到这个问题 2.解决步骤 方案1:删除node_modules和package-lock.json文件重新npm install下包,部分码农通过这个步骤可解决 方案2:node版本或者npm版本不对,或者没…

android WMS服务

android WMS服务 WMS的定义 窗口的分类 WMS的启动 WindowManager Activity、Window、DecorView、ViewRootImpl 之间的关系 WindowToken WMS的定义 WMS是WindowManagerService的简称&#xff0c;它是android系统的核心服务之一&#xff0c;它在android的显示功能中扮演着…