【C++】string 类

news2024/11/24 11:59:41

1. 标准库中的string类

注意:

1. string是表示字符串的字符串类

2. 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。 比特就业课

3. string在底层实际是:basic_string模板类的别名,typedef basic_string string;

4. 不能操作多字节或者变长字符的序列。 在使用string类时,必须包含#include头文件(#include<string>)以及using namespace std;

a. string类对象的常见构造

代码举例1

#include <iostream>
#include<string>
using namespace std;
int main()
{
	string t1; // 相当于类对象的实例化
}

代码举例2

#include <iostream>
#include<string>
using namespace std;
int main()
{
	string t1("hello world"); // 调用构造函数
	cout << t1 << endl;
	string t2 = "hello world"; //隐式类型转换(构造函数 + 拷贝构造 + 优化 -> 构造函数)
	cout << t2 << endl;
}

代码举例3

#include <iostream>
#include<string>
using namespace std;
int main()
{
	string t1(10, 'a');  // 拷贝 10 个 a
	cout <<  t1 << endl;
}

运行结果:

代码举例4

#include <iostream>
#include<string>
using namespace std;
int main()
{
	string t1("hello");
	string t2(t1); // 拷贝构造
	cout << t2 << endl;
}

b. string类对象的容量操作

  • size (返回字符串有效字符长度,没有 '\0 ')

代码举例1

#include <iostream>
#include<string>
using namespace std;
int main()
{
	string t1 = "hello";
	cout << t1.size() << endl;
}

运行结果:

  • capacity (返回字符串的总空间大小)

代码举例2

#include <iostream>
#include<string>
using namespace std;
int main()
{
	string t1 = "hello";
	cout << t1.capacity() << endl;
}

运行结果:

分析:

string 类里面的成员变量有两个可以存储空间,一个是数组,另一个是动态开辟的空间,当数组空间不足时,才会用动态开辟

  • reserve(扩大字符串容量,字符有效长度不变:即 size 不变)

代码举例3

#include <iostream>
using namespace std;
int main()
{
	string t1 = "hello";
	cout << "有效长度:" << t1.size() << " 总容量:" << t1.capacity() << endl;
	t1.reserve(100);
	cout << "有效长度:" << t1.size() << " 总容量:" << t1.capacity() << endl;
}

运行结果:

分析:

有些编译器在分配空间的时候,可能会对于开辟所需的空间再给大一点

  • resize (将有效字符的个数该成n个,多出的空间用字符c填充)

代码举例4

#include <iostream>
using namespace std;
int main()
{
	string t1 = "hello";
	cout << "有效长度:" << t1.size() << " 总容量:" << t1.capacity() << endl;
	t1.resize(100);
	cout << "有效长度:" << t1.size() << " 总容量:" << t1.capacity() << endl;
	t1.resize(10); //可以缩小有效长度,但总容量不会随意变动
	cout << "有效长度:" << t1.size() << " 总容量:" << t1.capacity() << endl;
	t1.resize(20, '*'); //对于的空间可以初始化任意字符
	cout << t1 << endl;
}

运行结果:

c. string类对象的访问及遍历操作

  • operator[] (返回pos位置的字符,和 C 语言的用法一样,const string类对象调用)
  • begin + end (begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器)

代码举例1

#include <iostream>
using namespace std;
int main()
{
	string t1 = "hello bit";
	string::iterator it = t1.begin();
	// it 相当于拿到 首元素的地址了
	while (it != t1.end())
	{
		cout << *it << endl;
		it++;
	}
}

运行结果:

分析:

  • rbegin + rend (rbegin获取最后一个字符的迭代器 + rend获取第一个字符前一个位置的迭代器)

代码举例2

#include <iostream>
using namespace std;
int main()
{
	string t1 = "hello bit";
	string::reverse_iterator rit = t1.rbegin();
	// it 相当于拿到 首元素的地址了
	while (rit != t1.rend())
	{
		cout << *rit << endl;
		rit++;
	}
}

运行结果:

分析:

  • 范围for

代码举例3

#include <iostream>
using namespace std;
int main()
{
	string t1 = "hello bit";
	for (auto i : t1)
	{
		cout << i;
	}
	cout << endl;
	for (int i = 0; i < t1.size(); i++)
	{
		cout << t1[i];
	}
}

运行结果:

d. string类对象的修改操作

  • push_back (在字符串后面增加一个字符)

代码举例1

#include <iostream>
using namespace std;
int main()
{
	string t1 = "hello";
	t1.push_back('a');
	t1.push_back('a');
	t1.push_back('a');
	cout << t1 << endl;
}

运行结果:

  • append (在字符串后面再增加一个字符串)

代码举例2

#include <iostream>
using namespace std;
int main()
{
	string t1 = "hello";
	t1.append("abcd");
	cout << t1 << endl;
}

运行结果:

  • operator+= (在字符串后面加一个字符或者一个字符串)

代码举例3

#include <iostream>
using namespace std;
int main()
{
	string t1 = "hello";
	t1 += "aabc";
	t1 += '*';
	cout << t1 << endl;
}

运行结果:

  • c_str (返回存储的字符串)

代码举例4

#include <iostream>
using namespace std;
int main()
{
	string t1 = "hello";
	t1 += '\0';
	t1 += 'a';
	cout << t1 << endl;
	cout << t1.c_str();
}

运行结果:

分析:

c_str() 是直接返回字符串 ,所以遇到 '\0' 就终止了

的完成是根据_size去遍历每个字符串

  • find + npos (从字符串pos位置开始往后找字符c,返回第一次遇到的该字符在字符串中的位置)

代码举例5

#include <iostream>
using namespace std;
int main()
{
	string t1 = "hello";
	cout << t1.find('o',2) << endl;
	// 从下标为 2 的位置去找字符 'o'
	cout << t1.find("lo") << endl;
	// 默认从下标 0 的位置去找字符串
}

注意:

  1. 如果找不到,返回 npos ( size_t npos = -1)
  2. 默认 pos 从 0 下标开始
  • rfind(从字符串pos位置开始往前找字符c,返回第一次遇到该字符在字符串中的位置)

代码举例6

#include <iostream>
using namespace std;
int main()
{
	string t1 = "hello";
	cout << t1.rfind('l') << endl;
}

运行结果:

注意:

  1. 如果找不到,返回 npos ( size_t npos = -1)
  2. 默认 pos 从 字符串中的最后一个字符(不是 '\0' ) 下标开始

e. string类非成员函数

  • operator>> (输入运算符重载)
  • operator<< (输出运算符重载)
  • getline (获取一行字符串)

代码举例

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string t1;
	getline(cin, t1);
	cout << t1 << endl;
	return 0;
}

注意:

getline 遇到空格不会结束

cin 遇到空格会结束

 2. string 类的模拟

namespace lhy
{
	class string
	{
	public:
		typedef char* iterator;
		typedef const char* const_iterater;
		iterator begin()
		{
			return _str;
		}
		iterator end()
		{
			return _str + _size;
		}
		const_iterater begin() const
		{
			return _str;
		}
		const_iterater end() const
		{
			return _str + _size;
		}
		string(const char* str = "")
			:_size(strlen(str))
		{
			_capacity = _size == 0 ? 3 : _size;
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}
		string(const string& t)
			:_size(strlen(t._str))
		{
			_capacity = t._size;
			_str = new char[_capacity + 1];
			strcpy(_str, t._str);
		}
		string(int n, char ch)
		:_size(n)
		{
			_capacity = _size;
			_str = new char[_capacity + 1];
			for (int i = 0; i < n; i++)
			{
				_str[i] = ch;
			}
			_str[_capacity] = '\0';
		}
		string& operator=(const string& t)
		{
			_size = t._size;
			_capacity = t._capacity;
			char* tmp = new char[_capacity + 1];
			strcpy(tmp, t._str);
			delete[] _str;
			_str = tmp;
			return *this;
		}
		char& operator[](int pos)
		{
			assert(pos < _size);
			return _str[pos];
		}
		const char& operator[](int pos) const 
		{
			assert(pos < _size);
			return _str[pos];
		}
		size_t size() const
		{
			return _size;
		}
		const char* c_str() const
		{
			return _str;
		}
		bool operator>(const string& t) const
		{
			if (strcmp(_str, t._str) > 0)
			{
				return true;
			}
			return false;
		}
		bool operator==(const string& t) const
		{
			if (strcmp(_str, t._str) == 0)
			{
				return true;
			}
			return false;
		}
		bool operator<(const string& t) const
		{
			if (strcmp(_str, t._str) < 0)
			{
				return true;
			}
			return false;
		}
		bool operator<=(const string& t) const
		{
			return *this < t || *this == t;
		}
		bool operator>=(const string& t) const
		{
			return *this > t || *this == t;
		}
		bool operator!=(const string& t) const
		{
			return !(*this == t);
		}
		void push_back(const char ch)
		{
			if (_size + 1 > _capacity)
			{
				reserve(_size * 2);
			}
			_size++;
			_str[_size - 1] = ch;
			_str[_size] = '\0';
		}
		void append(const char* str)
		{
			int len = strlen(str);
			if (_size + len > _capacity)
			{
				reserve(_size + len);
			}
			strcpy(_str + _size, str);
			_size += len;
		}
		void reserve(size_t n)
		{
			if (n > _size)
			{
				char* tmp = new char[n + 1];
				strcpy(tmp, _str);
				delete[] _str;
				_str = tmp;
				_capacity = n;
			}
		}
		void resize(size_t size,char ch = '\0')
		{
			if (size > _size)
			{
				reserve(size);
				int x = size - _size;
				while (x--)
				{
					*this += ch;
				}
				_size = size;
			}
			else
			{
				_size = size;
				_str[_size] = '\0';
			}
		}
		void insert(size_t pos,const char ch)
		{
			assert(pos <= _size);
			if (_size + 1 > _capacity)
			{
				reserve(_size * 2);
			}
			_size++;
			for (int i = _size; i > pos; i--)
			{
				_str[i] = _str[i - 1];
			}
			_str[pos] = ch;
		}
		void insert(size_t pos,const char* str)
		{
			assert(pos <= _size);
			int len = strlen(str);
			if (_size + len > _capacity)
			{
				reserve(_size + len);
			}
			_size += len;
			for (size_t i = _size; i > pos + len - 1; i--)
			{
				_str[i] = _str[i - len];
			}
			strncpy(_str + pos, str, len);
		}
		void erase(size_t pos,size_t n = npos)
		{
			assert(pos <= _size);
			if (n == npos || pos + n >= _size )
			{
				_str[pos] = '\0';
				_size = pos;
			}
			else
			{
				for (int i = pos + n; i <= this->size(); i++)
				{
					_str[i - n] = _str[i];
				}
				_size -= n;
			}
		}
		void swap(string &t)
		{
			std::swap(_size, t._size);
			std::swap(_capacity, t._capacity);
			std::swap(_str, t._str);

		}
		size_t find(const char ch, size_t pos = 0)
		{
			assert(pos < _size);
			for (size_t i = pos; i < this->size(); i++)
			{
				if (_str[i] == ch)
				{
					return i;
				}
			}
			return -1;
		}
		size_t find(const char* str, size_t pos = 0)
		{
			assert(pos < _size);
			char *tmp = std ::strstr(_str + pos, str);
			if (tmp == nullptr)
			{
				return -1;
			}
			else
			{
				return tmp - _str;
			}
		}
		string& operator+=(const char *str)
		{
			append(str);
			return *this;
		}
		string& operator+=(const char ch)
		{
			push_back(ch);
			return *this;
		}
		void clear()
		{
			_str[0] = '\0';
			_size = 0;
		}
		~string()
		{
			delete[] _str;
			_str = nullptr;
		}

	private:
		char* _str;
		size_t _size;
		size_t _capacity;
		static size_t npos;
	};
	size_t string::npos = -1;
	ostream& operator<<(ostream& out, const string& t)
	{
		for (size_t i = 0; i < t.size(); i++)
		{
			out << t[i];
		}
		return out;
	}
	istream& operator>> (istream& in,string& t)
	{
		t.clear();
		int i = 0;
		char tmp[128];
		char ch = in.get();
		while (ch != ' ' && ch != '\n')
		{
			tmp[i++] = ch;
			if (i == 126)
			{
				tmp[i + 1] = '\0';
				t += tmp;
				i = 0;
			}
			ch = in.get();
		}
		if (i != 0)
		{
			tmp[i] = '\0';
			t += tmp;
		}
		return cin;
	}
}

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

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

相关文章

知识图谱与LLMs:微调 VS RAG、LLM的局限性以及如何克服

原文地址&#xff1a;Knowledge Graphs & LLMs: Fine-Tuning Vs. Retrieval-Augmented Generation 2023 年 6 月 6 日 GitHub&#xff1a;https://github.com/neo4j/NaLLM 大型语言模型 (LLM) 的第一波炒作来自 ChatGPT 和类似的基于网络的聊天机器人&#xff0c;相信在…

国货当自强,亿道3款手持新品同步上市

深圳市亿道信息股份有限公司是国内知名的加固型移动计算机提供商&#xff0c;同时也是国内较大的行业定制及终端产品方案公司之一。 过去我们一直专注于平板电脑集成RFID射频识别、电子标签技术的研发生产与销售&#xff0c;以成熟的平板电脑制造技术&#xff0c;为客户提供RF…

重学SpringBoot3-日志Logging

重学SpringBoot3-日志Logging 引言默认日志配置日志门面如何实现默认配置 自定义日志配置日志级别日志分组日志格式日志输出自定义 Logback 配置切换日志框架 日志使用方式一&#xff1a;LoggerFactory 获取Logger对象方式二&#xff1a;引入 lombok 总结 引言 日志记录是任何…

记录一则 线上域名证书更新及cdn证书更新

本篇为阿里云免费证书更新记录。 登录阿里云账号 搜索数字证书管理服务管理控制台 点击创建证书 输入你的域名 填写相关信息&#xff08;注&#xff1a;域名验证方式选择文件验证&#xff09; 等待审核通过&#xff08;时间不久&#xff0c;一般为半小时内&#xff09; …

RabbitMQ(三):AMQP协议

目录 1 AMQP协议1.1 AMQP协议介绍1、AMQP是什么2、消息代理中间件的职责 1.2 AMQP 0-9-1模型1、AMQP的工作过程2、交换器和交换器类型3、队列队列属性队列名称队列持久化 1.3 几个概念1、绑定2、消费者3、消息确认4、预取消息5、消息属性和有效载荷&#xff08;消息主体&#x…

leetcode 经典题目42.接雨水

链接&#xff1a;https://leetcode.cn/problems/trapping-rain-water 题目描述 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 思路分析 首先&#xff0c;我们需要遍历数组&#xff0c;对于每个元素&am…

探秘C语言:如何轻松求解正整数公因子个数?

本篇博客会讲解力扣“2427. 公因子的数目”的解题思路&#xff0c;这是题目链接。 本题的思路是&#xff1a; 由于a和b公因子的个数就是a和b的最大公约数的因子的个数&#xff0c;所以我们需要思考以下2个问题&#xff1a; 如何求解最大公约数&#xff1f;如何求解正整数的因…

性能测试总结 —— 基础理论篇!

随着软件行业的快速发展&#xff0c;现代的软件系统越来越复杂&#xff0c;功能越来越多&#xff0c;测试人员除了需要保证基本的功能测试质量&#xff0c;性能也随越来越受到人们的关注。但是一提到性能测试&#xff0c;很多人就直接连想到Loadrunner。认为LR就等于性能测试&a…

事件流、事件捕获、事件冒泡、事件委托

一、事件流 事件流指的是事件完整执行过程中的流动路径&#xff0c;分为捕获阶段、冒泡阶段。如上图 二、事件捕获 当一个元素的事件被触发时&#xff0c;会从DOM的根元素开始&#xff0c;依次调用同名事件&#xff08;从外到里&#xff0c;从父到子&#xff09;。 DOM.addEve…

【MySQL】数据库设计

目录 数据库设计基本任务 软件项目开发周期中数据库设计数据库设计的基本步骤解释需求分析需求分析的三个步骤&#xff1a;1.需求调查:2.分析数据字典内容定义数据的方法案例 3. 评审 概念结构设计概念模型概念结构设计E-R图概念模型组成元素&#xff1a;关系解释案例分析 逻辑…

网络安全: Kali Linux 进行 SSH 渗透与防御

目录 一、实验 1.环境 2.nmap扫描目标主机 3.Kali Linux 进行 SSH 渗透 3.Kali Linux 进行 SSH 防御 二、问题 1.SSH有哪些安全配置 一、实验 1.环境 &#xff08;1&#xff09;主机 表1 主机 系统版本IP备注Kali Linux2022.4 192.168.204.154&#xff08;动态&…

基于springboot+vue的农商对接系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

110. 平衡二叉树【简单】

110. 平衡二叉树【简单】 题目描述&#xff1a; 给定一个二叉树&#xff0c;判断它是否是高度平衡的二叉树。 本题中&#xff0c;一棵高度平衡二叉树定义为&#xff1a; 一个二叉树每个节点的左右两个子树的高度差的绝对值不超过 1 。 示例 1&#xff1a; 输入&#xff1a;r…

Vivado HLS学习笔记

任意精度的数据类型 u 代表 unsigned&#xff0c;fixed代表定点数据&#xff0c;即常数 采用任意精度的数据类型可以使用更少的资源&#xff0c;硬件友好性 数据类型定义在 header file 中 表示任意进制 ap_int<6> a("101010",2); //二进制数据101010 ap_in…

DR模式下部署LVS负载均衡集群的详细原理

目录 一、LVS-DR模式 1、基本原理 2、数据包流向分析 二、LVS-DR中的ARP问题 三、LVS-DR 特点 3.1 DR模式的特点 3.2 LVS-DR的优缺点 四、RS设置lo:0而不设置ens33:0的原因 一、LVS-DR模式 1、基本原理 Director Server作为群集的访问入口&#xff0c;但不作为网关使…

【C++实战项目】Date日期类 --- 运算符重载的深入探索

&#x1f4f7; 江池俊&#xff1a;个人主页 &#x1f525; 个人专栏&#xff1a;✅C那些事儿 ✅Linux技术宝典 &#x1f305; 此去关山万里&#xff0c;定不负云起之望 文章目录 引言一、为什么需要运算符重载&#xff1f;二、日期类的实现1. 基本框架2. 预备工作3. Date 类…

【MySQL】数据库的操作(1)

【MySQL】数据库的操作&#xff08;1&#xff09; 目录 【MySQL】数据库的操作&#xff08;1&#xff09;创建数据库数据库的编码集和校验集查看系统默认字符集以及校验规则查看数据库支持的字符集查看数据库支持的字符集校验规则校验规则对数据库的影响数据库的删除 数据库的备…

预算有限,3D渲染更该升级显卡还是CPU?升级电脑配置推荐!

在当今数字化时代&#xff0c;影视、游戏和效果图设计等领域都需要强大的计算机来支持3D渲染工作。受当前国际和市场环境影响&#xff0c;硬件价格持续上涨&#xff0c;有专家预测这种局面将至少持续半年以上。因此&#xff0c;在预算有限的情况下&#xff0c;很多设计师在电脑…

Spring Cloud Gateway核心之Predicate

路由 Predicate 工厂 Spring Cloud Gateway 将路由作为 Spring WebFluxHandlerMapping基础设施的一部分进行匹配。Spring Cloud Gateway 包含许多内置的路由Predicate 工厂。所有这些谓词都匹配 HTTP 请求的不同属性。多个 Route Predicate Factory 可以组合&#xff0c;并通过…

【VTKExamples::PolyData】第四十八期 ShrinkPolyData

很高兴在雪易的CSDN遇见你 VTK技术爱好者 QQ:870202403 前言 本文分享VTK样例ShrinkPolyData,并解析接口vtkShrinkPolyData,希望对各位小伙伴有所帮助! 感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步! 你的点赞就是我的动力(^U^)ノ~YO 1. ShrinkPol…