从零到精通:用C++ STL string优化代码

news2024/12/26 11:59:36

目录

1:为什么要学习string类

2:标准库中的string类

2.1:string类(了解)

2.2:总结

3:string类的常用接口

3.1:string类对象的常见构造

3.1.1:代码1

3.1.2:代码2

3.2:string类对象的遍历操作

3.2.1:代码1(begin + end)

3.2.2:代码2(rbegin + rend)

3.3:string类对象的容量遍历

3.3.1:代码1(测试容量)

3.3.2:代码2(测试resize)

3.3.3:代码3(测试reserve)

3.4:string对象的访问

3.5:string类对象的修改操作

3.5.1:代码1

3.5.2:代码2

3.5.3:代码3

3.6:string类的非成员函数

4:vs下与g++下string结构的说明

4.1:vs下string的结构

4.2:g++下的string

hello,家人们,今天咱们来介绍string相关的操作,好啦,废话不多讲,开干.


1:为什么要学习string类

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

2:标准库中的string

2.1:string类(了解)

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

2.2:总结

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

3:string类的常用接口

3.1:string类对象的常见构造

3.1.1:代码1

#define  _CRT_SECURE_NO_WARNINGS
#include <iostream> 
using namespace std;
#include <string>

void test_constructor()
{
	//构造空的字符串对象即空字符串
	string s1;
	//使用字符串构造字符串对象
	string s2("hello world");
	//拷贝构造,将s2拷贝给s3
	string s3(s2);
	//拷贝字符串,并且只拷贝5个字符
	string s4("hello world", 5);
	cout << "s1" << s1 << endl;
	cout << "s2 = " << s2 << endl;
	cout << "s3 = " << s3 << endl;
	cout << "s4 = " << s4 << endl;
}

int main()
{
	test_constructor();
	return 0;
}

3.1.2:代码2

#define  _CRT_SECURE_NO_WARNINGS
#include <iostream> 
using namespace std;
#include <string>

void test_constructor()
{
	//从下标为3的位置开始拷贝字符串,拷贝12个字符串
	string s5("you are welcome", 3, 12);
	//使用字符'*'填充对象s6,填充10个
	string s6(10, '#');
	string s7;
	//赋值运算符重载
	s7 = s5;
	cout << "s5 = " << s5 << endl;
	cout << "s6 = " << s6 << endl;
	cout << "s7 = " << s7 << endl;
}

int main()
{
	test_constructor();
	return 0;
}

3.2:string类对象的遍历操作

3.2.1:代码1(begin + end)

#define  _CRT_SECURE_NO_WARNINGS
#include <iostream> 
using namespace std;
#include <string>

void test_string_iterators()
{
	string str("how are you");
	//获取指向第一个字符的迭代器
	std::string::iterator it = str.begin();
	while(it != str.end())
	{
		cout << *it;
		it++;
	}
}

int main()
{
	test_string_iterators();
	return 0;
}

3.2.2:代码2(rbegin + rend)

#define  _CRT_SECURE_NO_WARNINGS
#include <iostream> 
using namespace std;
#include <string>

void test_string_reverse_iterators()
{
	string str("how are you");
	//使用反向迭代器时需要指定类域
	string::reverse_iterator rit = str.rbegin();
	string::reverse_iterator ren = str.rend();
	while(rit != str.rend())
	{
		cout << *rit;
		++rit;
	}
}

int main()
{
	test_string_reverse_iterators();
	return 0;
}

3.3:string类对象的容量遍历

3.3.1:代码1(测试容量)

#define  _CRT_SECURE_NO_WARNINGS
#include <iostream> 
using namespace std;
#include <string>

void test_string_capacity()
{
	string str("hello world");
	//返回字符串的长度
	cout << "size:>" << str.size() << endl;
	cout << "length:>" << str.length() << endl;
	//返回字符串所能触及的最大长度
	cout << "max_size:>" << str.max_size() << endl;
	//返回当前对象所分配的容量大小
	cout << "capacity:>" << str.capacity() << endl;

	//清空字符串但是不影响容量
	str.clear();
	cout << "size:>" << str.size() << endl;
	cout << "capacity:>" << str.capacity() << endl;
	//判断字符串是否为空
	str = "hello world";
	int result = str.empty();
	cout <<"清空前:>" << result << endl;
	str.clear();
	cout <<"清空后:>" << str.empty() << endl;

	//默认将capacity缩到15
	str.shrink_to_fit();
	cout << "size:>" << str.size() << endl;
	cout << "capacity:>" << str.capacity() << endl;
}

int main()
{
	test_string_capacity();
	return 0;
}

3.3.2:代码2(测试resize)

#define  _CRT_SECURE_NO_WARNINGS
#include <iostream> 
using namespace std;
#include <string>

void test_string_resize()
{
	string str("hello world");
	//比size小则进行删除
	str.resize(10);
	cout << "size:>" << str.size() << endl;
	cout << "capacity:>" << str.capacity() << endl;
	cout << str << endl;
	
	cout << endl;
	//比size大但小于capacity会用改变size,并用\0插入
	str.resize(13);
	cout << "size:>" << str.size() << endl;
	cout << "capacity:>" << str.capacity() << endl;
	cout << str << endl;

	//比capacity大,会先改变size的大小同时进行扩容
	str.resize(20);
	cout << "size:>" << str.size() << endl;
	cout << "capacity:>" << str.capacity() << endl;
	cout << str << endl;
}

int main()
{
	test_string_resize();
	return 0;
}

3.3.3:代码3(测试reserve)

#define  _CRT_SECURE_NO_WARNINGS
#include <iostream> 
using namespace std;
#include <string>

void test_string_reserve()
{
	string str("hello world");
	cout << "size:>" << str.size() << endl;
	cout << "capacity:>" << str.capacity() << endl;
	cout << "reserver后" << endl;

	cout << endl;

	//比size小不变化
	str.reserve(10);
	cout << "size:>" << str.size() << endl;
	cout << "capacity:>" << str.capacity() << endl;
	cout << str << endl;
	
	cout << endl;
	//比size大但小于capacity也不发生变化
	str.reserve(13);
	cout << "size:>" << str.size() << endl;
	cout << "capacity:>" << str.capacity() << endl;
	cout << str << endl;

	cout << endl;

	//比capacity大才会进行扩容
	str.reserve(20);
	cout << "size:>" << str.size() << endl;
	cout << "capacity:>" << str.capacity() << endl;
	cout << str << endl;
}

int main()
{
	test_string_reserve();
	return 0;
}

  • clear只是将string中的有效字符清空,不改变底层的空间大小.
  • resize(size_t n)与resize(size_n,char c)都是将字符串中的有效字符个数改变到n个,不同的是,当字符个数增多时:resize(n)0来填充多出的元素空间,resize(size_n,char c)用字符c来填充多出的空间.
  • reserve(size res_arg):为string预留空间,不改变有效元素,只有在reserve的参数大于底层的空间总大小时 reserve才会进行扩容.

3.4:string对象的访问

#define  _CRT_SECURE_NO_WARNINGS
#include <iostream> 
using namespace std;
#include <string>

void test_string_element_access()
{
	string s1("hello world");
	for(size_t i = 0; i < s1.size(); i++)
	{
		cout << s1[i] << " ";
	}

	cout << endl;
	for (size_t i = 0; i < s1.size(); i++)
	{
		cout << s1.operator[](i) << " ";
	}
	cout << endl;

	//获取尾部元素
	cout << s1.back() << endl;
	//获取头部元素
	cout << s1.front() << endl;
	cout << s1.at(0) << endl;
}

int main()
{
	test_string_element_access();
	return 0;
}

3.5:string类对象的修改操作

3.5.1:代码1
 

#define  _CRT_SECURE_NO_WARNINGS
#include <iostream> 
using namespace std;
#include <string>

void test_string_Modifiers()
{
	string s1("hello world");
	string s2("bit");

	//operator+=运算符重载
	s1 += s2;
	s1 += 'c';
	s1 += "bit";
	cout << s1 << endl;
	cout << endl;

	//append
	s1.append(" hello world");
	cout << s1 << endl;

	//给对象s1分配新内容,并且代替当初的字符串内容
	s1.assign(" xxxxxx");
	cout << s1 << endl;
}

int main()
{
	test_string_Modifiers();
	return 0;
}

3.5.2:代码2

#define  _CRT_SECURE_NO_WARNINGS
#include <iostream> 
using namespace std;
#include <string>

void test_string_Modifiers()
{
	string s1("hello world");
	string s2("bit");

	//在下标为5的位置插入字符串0
	s1.insert(5, "0");
	cout << s1 << endl;
	cout << endl;
	//从下标为5的位置开始抹除,抹除的长度为3
	s1.erase(5, 3);
	cout << s1 << endl;
	cout << endl;

	//交换两个字符串的内容
	s1.swap(s2);
	cout<<"s1 == " << s1 << endl;
	cout<<"s2 == " << s2 << endl;
}

int main()
{
	test_string_Modifiers();
	return 0;
}

3.5.3:代码3

#define  _CRT_SECURE_NO_WARNINGS
#include <iostream> 
using namespace std;
#include <string>

void test_string_operatorions()
{
	string s1("hello world");
	string s2("bit");

	//返回C类型的字符串
	cout << s1.c_str() << endl;
	cout << s2.c_str() << endl;

	//find
	//查找字符,默认从首元素开始
	cout << s1.find(' ') << endl;
	//查找字符,从下标为5的位置开始
	cout << s1.find(' ', 5) << endl;
	//查找字符串,返回出现该字符串的首字符位置,类似于strstr
	cout << s1.find("world") << endl;
	cout << endl;
	//rind
	//查找最后一次出现该字符的位置
	cout << s1.rfind('l') << endl;
	//查找最后一次出现该字符串的位置
	cout << s1.rfind("wo") << endl;
	cout << endl;

	size_t position = s1.find(' ');
	//从position + 1的位置开始取后面字符串
	cout << s1.substr(position + 1);
}

int main()
{
	test_string_operatorions();
	return 0;
}

3.6:string类的非成员函数

#define  _CRT_SECURE_NO_WARNINGS
#include <iostream> 
using namespace std;
#include <string>

void test_string_Non_member_function_overloads()
{
	string s1("hello world");
	string s2("hello world");
	string s3("hello xorld");

	cout << (s1 == s2) << endl;
	cout << (s1 > s2) << endl;
	cout << endl;

	//读取一行字符串
	getline(cin, s1);

	string::iterator it = s1.begin();
	string::iterator end = s1.end();

	cout << s1 << endl;

	cout << endl;
	//区间为左闭右开,反转字符串
	reverse(it, end);
	cout << s1 << endl;
}

int main()
{
	test_string_Non_member_function_overloads();
	return 0;
}

4:vs下与g++下string结构的说明

PS:这是在32位平台下进行验证滴,32位平台下,指针占4个字节

4.1:vs下string的结构

string总共占28个字节,内部结构稍微复杂些,先是有一个联合体,联合体用来定义string中字符串的存储空间:

  • 当字符串长度 < 16时,使用内部固定的字符数组来进行存放
  • 当字符串长度 >= 16时,从堆区上开辟空间.
union _Bxty
{ // storage for small buffer or pointer to larger one
 value_type _Buf[_BUF_SIZE];
 pointer _Ptr;
 char _Alias[_BUF_SIZE]; // to permit aliasing
} _Bx;
  1. 这种设计也是有一定道理的,大多数情况下字符串的长度都小于16,那string对象创建好之后,内部已经有了16个字符数组的固定空间,不需要通过堆创建,效率高.
  2. 还有一个size_t字段保存字符串长度,一个size_t字段保存从堆上开辟空间总的容量.
  3. 有一个指针 做一些其他事情.
    因此总共占 16 + 4 + 4 + 4 = 28个字节.

 

4.2:g++下的string

g++下,string是通过写时拷贝实现的,string对象总共占4个字节,内部只包含了一个指针,该指针将来指向一块堆空间,内部包含了如下字段:
        
  1. 空间总大小.
  2. 字符串有效长度.
  3. 引用计数.
  4. 指向堆空间的指针,用来存储字符串
struct _Rep_base
{
 size_type _M_length;
 size_type _M_capacity;
 _Atomic_word _M_refcount;
};

 好啦,uu们,string的这部分滴详细内容博主就讲到这里啦,如果uu们觉得博主讲的不错的话,请动动你们滴小手给博主点点赞,你们滴鼓励将成为博主源源不断滴动力,同时也欢迎大家来指正博主滴错误~

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

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

相关文章

ESD防静电监控系统助力电子制造行业转型升级

在电子制造行业中&#xff0c;静电危害不容小觑。ESD 防静电监控系统的出现&#xff0c;为行业转型升级带来强大助力。电子元件对静电极为敏感&#xff0c;微小的静电放电都可能损坏元件&#xff0c;影响产品质量。ESD 防静电监控系统能够实时监测生产环境中的静电状况&#xf…

Python制作爱心跳动代码,这就是程序员的烂漫吗

最近有个剧挺火的 就是那个程序员的剧&#xff0c;叫什么温暖你来着 咳咳&#xff0c;剧我没怎么看&#xff0c;但是吧&#xff0c;里面有个爱心代码&#xff0c;最近可是蛮火的&#xff0c;今天就用Python来尝试一下吧 怎么说呢&#xff0c;用这个表白也可以的&#xff0c;万…

计算机网络(运输层)

运输层概述 概念 进程之间的通信 从通信和信息处理的角度看&#xff0c;运输层向它上面的应用层提供通信服务&#xff0c;它属于面向通信部分的最高层&#xff0c;同时也是用户功能中的最低层。 当网络的边缘部分中的两个主机使用网络的核心部分的功能进行端到端的通信时&a…

数量多怎么打印最便宜?

当您面临大量文件需要打印时&#xff0c;如何找到既经济又高效的打印解决方案成为关键。在众多打印服务中&#xff0c;琢贝云打印凭借其显著的价格优势和服务特色&#xff0c;成为众多用户的首选。 极致低价&#xff0c;成本更低 黑白打印超低价&#xff1a;提供的黑白打印服…

照明风暖浴霸语音控制芯片,智能声控开关芯片方案NRK3301

照明风暖浴霸通过特制的防水红外线热波管&#xff0c;与换气扇的巧妙组合&#xff0c;将浴室的取暖、红外线理疗、浴室换气、装饰等多种功能结合于一体的浴用小家电产品&#xff1b;为了提升产品的卖点&#xff0c;许多厂商都在尝试加各色各样的功能&#xff0c;某厂家加入了NR…

分销--分销人员管理系统架构文档

1. 概述 1.1 目的 本系统架构文档旨在描述分销人员管理系统的整体设计与结构&#xff0c;明确系统的功能模块、流程和技术实现&#xff0c;确保系统能够有效支持分销员的招募、管理及监督。 1.2 范围 本文档涵盖了分销员招募与管理。包括分销员列表、招募流程等。 2. 系统…

基于人工智能的垃圾分类图像识别系统

目录 引言项目背景环境准备 硬件要求软件安装与配置系统设计 系统架构关键技术代码示例 数据预处理模型训练模型预测应用场景结论 1. 引言 随着全球环境保护意识的增强&#xff0c;垃圾分类逐渐成为城市治理的关键任务之一。通过人工智能技术&#xff0c;尤其是图像识别系统…

Ascend C算子性能优化实用技巧03——搬运优化

Ascend C是CANN针对算子开发场景推出的编程语言&#xff0c;原生支持C和C标准规范&#xff0c;兼具开发效率和运行性能。使用Ascend C&#xff0c;开发者可以基于昇腾AI硬件&#xff0c;高效的实现自定义的创新算法。 目前已经有越来越多的开发者使用Ascend C&#xff0c;我们…

java控制流程

1.块作用域 用一对大括号括起来的就是一个块&#xff0c;块确定了变量的作用域。一个块可以嵌套在另一个块中。块外的变量在块内有效&#xff0c;而块内的变量在块外无效。 public class Main{public static void main(String[] args){int i1;{System.out.println("i&qu…

【2024】JAVA实现响应式编程Reactor具体API文档使用说明

目录&#x1f4bb; 前言一、简介1、响应式编程概述背景知识什么是响应式编程具体概述应用场景:常用的库和框架 二、 Reactor实现响应式编程1、Flux 和 Mono介绍Flux:Mono:Flux 和 Mono 的区别:Flux 和 Mono 的关系: 2、常用API使用添加依赖2.1、生产流常用汇总 2.1.1、直接创建…

2024 高教社杯 数学建模国赛 (A题)深度剖析|“板凳龙” 闹元宵|数学建模完整代码+建模过程全解全析

当大家面临着复杂的数学建模问题时&#xff0c;你是否曾经感到茫然无措&#xff1f;作为2022年美国大学生数学建模比赛的O奖得主&#xff0c;我为大家提供了一套优秀的解题思路&#xff0c;让你轻松应对各种难题&#xff01; CS团队倾注了大量时间和心血&#xff0c;深入挖掘解…

设计模式之装饰器模式:让对象功能扩展更优雅的艺术

一、什么是装饰器模式 装饰器模式&#xff08;Decorator Pattern&#xff09;是一种结构型设计模式&#xff08;Structural Pattern&#xff09;&#xff0c;它允许用户通过一种灵活的方式来动态地给一个对象添加一些额外的职责。就增加功能来说&#xff0c;装饰器模式相比使用…

“Jmeter-InfluxDB-Grafana“常见错误有哪些如何解决?

常见错误&#xff1a; 1.网络不同&#xff0c;检查网络IP是否写对&#xff0c;端口号有没有放开&#xff08;Centos7端口号命令&#xff09;&#xff0c;防火墙是否关闭 firewall-cmd --add-port3000/tcp --permanent firewall-cmd --add-port3000/udp --permanent firewall-…

中国剩余定理和扩展中国剩余定理(模板)

给你一元线性同余方程组&#xff0c;如下&#xff1a; 其中&#xff0c;当 , , ... , 两两互质的话就是中国剩余定理 &#xff0c; 不互质的话就是扩展中国剩余定理。 给出中国剩余定理的计算过程和扩展中国剩余定理的推理过程&#xff1a; #include<bits/stdc.h> us…

MT3516A-ASEMI三相整流桥MT3516A

编辑&#xff1a;ll MT3516A-ASEMI三相整流桥MT3516A 型号&#xff1a;MT3516A 品牌&#xff1a;ASEMI 封装&#xff1a;D-63 批号&#xff1a;2024 类型&#xff1a;三相整流桥 电流&#xff08;ID&#xff09;&#xff1a;35A 电压(VF)&#xff1a;1600V 安装方式&a…

C++开发基础之宏定义:入门、中级、高级用法示例解析

前言 在C开发中&#xff0c;宏定义是一种非常重要的预处理功能&#xff0c;能够简化代码、提高可读性、减少重复性工作。然而&#xff0c;宏的使用也存在一些潜在的风险&#xff0c;滥用宏可能导致代码难以调试和维护。在这篇博客中&#xff0c;我们将从入门、中级到高级&…

【数据库|第9期】SQL Server、Access和Sqlite 的字段别名详解

日期&#xff1a;2024年8月28日 作者&#xff1a;Commas 签名&#xff1a;(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释&#xff1a;如果您觉得有所帮助&#xff0c;帮忙点个赞&#xff0c;也可以关注我&#xff0c;我们一起成长&#xff1b;如果有不对的地方&#xf…

redis缓存的目的、场景、实现、一致性问题

文章目录 1、加缓存的目的&#xff08;作用&#xff09;&#xff1a;2、加缓存的场景&#xff1a;读多写少3、加不加缓存的标准&#xff1a;4、缓存的实现&#xff1a;5、缓存的实现方案&#xff1a;6、缓存的粒度问题7、缓存的一致性问题 专辑详情和声音详情属于并发量较高的数…

2024 高教社杯 数学建模国赛 (B题)深度剖析|生产过程中的决策问题|数学建模完整代码+建模过程全解全析

当大家面临着复杂的数学建模问题时&#xff0c;你是否曾经感到茫然无措&#xff1f;作为2022年美国大学生数学建模比赛的O奖得主&#xff0c;我为大家提供了一套优秀的解题思路&#xff0c;让你轻松应对各种难题&#xff01; CS团队倾注了大量时间和心血&#xff0c;深入挖掘解…

入门数据结构JAVA DS——如何实现简易的单链表(用JAVA实现)

前言 链表&#xff08;Linked List&#xff09;是一种线性数据结构&#xff0c;它由一系列节点组成&#xff0c;每个节点包含两个部分&#xff1a;存储数据的部分和指向下一个节点的指针&#xff08;或引用&#xff09;。链表的结构使得它能够动态地增长和收缩&#xff0c;适合…