C/C++ 入门(7)string类(STL)

news2024/9/22 7:36:53

个人主页:仍有未知等待探索-CSDN博客

专题分栏:C++

                                                        请多多指教!

目录

一、标准库中的string

1、了解

2、string类常用接口说明

1、常见的构造函数

2、容量操作 ​编辑

3、访问及遍历操作

4、修改操作

5、非成员函数

 二、string类实现

1、string类的大体框架

2、构造和析构函数 

3、迭代器 

4、成员函数 

5、非成员函数

 三、问题

1、深拷贝和浅拷贝问题

2、strcpy,memcpy

四、总代码


一、标准库中的string

1、了解

1、string是表示字符串的字符串类
2、该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。

2、string类常用接口说明

下面的函数都可以去下面的网址进行查文档,来看函数的功能。(接下来我会实现这个string类)

string - C++ Reference

1、常见的构造函数

string类对象的常见构造
函数名称功能说明
string()        构造空的string类,即空字符串
string(const char*s)

用c_str()来构造string类对象

string(size_t n, char c)string类对象中包含n个字符c
string(const string& s)拷贝构造函数

2、容量操作
 

3、访问及遍历操作

4、修改操作

5、非成员函数

 二、string类实现

实现string类能让我们更好的明白模板的使用,函数重载等等。

1、string类的大体框架

#include <iostream>
#include <cstring>
#include <assert.h>
using namespace std;

class string
{
public:

private:
	char* _str; // string存的字符串
	size_t _size; // string中字符串的长度 
	size_t _capacity; // string的容量
};

2、构造和析构函数 

string()
	:_str(nullptr)
	,_size(0)
	,_capacity(0)
{}
string(const char* str)
	:_size(strlen(str))
	,_capacity(_size)
{
	_str = new char[_capacity + 1];
	strcpy(_str, str);
}
string(const string& str)
	:_str(new char[str._capacity + 1])
	,_size(str._size)
	,_capacity(str._capacity)
{
	strcpy(_str, str._str);
}
~string()
{
	delete[] _str;
	_str = nullptr;
	_size = 0;
	_capacity = 0;
}

3、迭代器 

typedef char* iterator;
iterator begin()
{
	return _str;
}
iterator end()
{
	return _str + _size;
}

4、成员函数 


string& operator=(const string& str)
{
	char* tmp = new char[str._capacity + 1];
	strcpy(tmp, str._str);
	delete[] _str;
	_str = tmp;
	_size = str._size;
	_capacity = str._capacity;
	return *this;
}
void reserve(int x)
{
	if (_capacity < x)
	{
		char* tmp = new char[x + 1];
		strcpy(tmp, _str);
		delete[] _str;
		_str = tmp;
		_capacity = x;
	}
}
void swap(string& str)
{
	std::swap(_str, str._str);
	std::swap(_size, str._size);
	std::swap(_capacity, str._capacity);
}
const char* c_str() const
{
	return _str;
}
void clear()
{
	_str[0] = '\0';
	_size = 0;
}
void insert(int index, const string& str)
{
	int len = str._size;
	assert(index >= 0 && index < _size);
	if (_size + len >= _capacity)
	{
		reserve(_capacity + len);
	}
	for (int i = _size - 1; i >= index; i -- )
	{
		_str[i + len] = _str[i];
	}
	for (int j = 0, i = index; j < str._size; j ++ ,i ++ )
	{
		_str[i] = str._str[j];
	}
	_size += len;
}
void insert(int index, char ch)
{
	assert(index >= 0 && index < _size);
	if (_size + 1 >= _capacity)
	{
		reserve(2 * _capacity);
		_capacity *= 2;
	}
	for (int i = _size - 1; i >= index; i -- )
	{
		_str[i + 1] = _str[i];
	}
	_str[index] = ch;
	_size ++ ;
	
}
void append(const string& str)
{
	int len = str._size;
	if (len + _size > _capacity)
	{
		reserve(len + _size);
		_capacity = len * _size;
	}
	int end = _size;
	for (int i = 0; i < str._size; i ++ ,end ++ )
	{
		_str[end] = str._str[i];
	}
	_size += len;
}
string& operator+=(const string& str)
{
	append(str);
	return *this;
}
void push_back(const char ch)
{
	if (_size + 1 >= _capacity)
	{
		reserve(2 * _capacity);
	}
	_capacity *= 2;
	_str[_size] = ch;
	_size ++ ;
}
int size() const
{
	return _size;
}
int capacity() const
{
	return _capacity;
}
bool empty() const
{
	return _size == 0;
}
void resize(int n, char ch = '\0')
{
	if (n < _size)
	{
		for (int i = n; i < _size; i ++ )
		{
			_str[i] = '\0';
		}
	}
	else if (n + 1 < _capacity)
	{
		for (int i = _size; i < n; i ++ )
		{
			_str[i] = ch;
		}
	}
	else
	{
		reserve(n);
	}
}
char& operator[](size_t index)
{
	assert(index < _size);
	return _str[index];
}
const char& operator[](size_t index)const
{
	assert(index < _size);
	return _str[index];
}
bool operator==(const string& str)
{
	int ret = strcmp(_str, str.c_str());
	return ret == 0;
}
bool operator!=(const string& str)
{
	return !(*this == str);
}
bool operator>(const string& str)
{
	int ret = strcmp(_str, str.c_str());
	return ret > 0;
}
bool operator<(const string& str)
{
	int ret = strcmp(_str, str.c_str());
	return ret < 0;
}
bool operator<=(const string& str)
{
	return *this < str || *this == str;
}
bool operator>=(const string& str)
{
	return *this > str || *this == str;
}
int find (char c, size_t pos = 0) const
{
	assert(pos < _size);
	for (int i = pos; i < _size; i ++ )
	{
		if (_str[i] == c) return i;
	}
	return npos;
}
int find (const char* s, size_t pos = 0) const
{
	char* p = strstr(_str + pos, s);
	if (p != nullptr)
	{
		return p - _str;
	}
	return npos;
}
string& erase (size_t pos = 0, size_t len = npos)
{
	assert(pos < _size);
	if (len == npos || len >= _size - pos)
	{
		_str[pos] = '\0';
		_size = pos;
	}
	else
	{
		int i = 0;
		for (i = pos + len; i < _size; i ++ )
		{
			_str[i - len] = _str[i];
		}
		_str[i] = '\0';
		_size -= len;
	}
	return *this;
}

5、非成员函数

    ostream& operator<<(ostream& out, const string& str)
	{
		int len = str._size;
		for (int i = 0; i < len; i ++ )
		{
			out << str._str[i];
		}
		return out;
	}
    istream& operator>>(istream& in, string& str)
	{
		str.clear();
		char ch = in.get();
		char buff[128];
		int i = 0;
		while (ch != ' ' && ch != '\n')
		{
			buff[i ++ ] = ch;
			if (i == 127)
			{
				buff[i] = '\0';
				str += buff;
				i = 0;
			}
			ch = in.get();
		}

		if (i != 0)
		{
			buff[i] = '\0';
			str += buff;
		}
		return in;
	}
}

 三、问题

1、深拷贝和浅拷贝问题

浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以当继续对资源进项操作时,就会发生发生了访问违规。


深拷贝:每个对象都有一份独立的资源,不要和其他对象共享。如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。一般情况都是按照深拷贝方式提供。

2、strcpy,memcpy

通过下面的例子也能清晰的看出来,这两个拷贝函数都是浅拷贝。所以在用的时候需要小心谨慎。

四、总代码

#include <iostream>
#include <cstring>
#include <assert.h>
using namespace std;

namespace my
{
	class string
	{
	public:
		string()
			:_str(nullptr)
			,_size(0)
			,_capacity(0)
		{}
		string(const char* str)
			:_size(strlen(str))
			,_capacity(_size)
		{
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}
		string(const string& str)
			:_str(new char[str._capacity + 1])
			,_size(str._size)
			,_capacity(str._capacity)
		{
			strcpy(_str, str._str);
		}
		~string()
		{
			delete[] _str;
			_str = nullptr;
			_size = 0;
			_capacity = 0;
		}
		typedef char* iterator;
		iterator begin()
		{
			return _str;
		}
		iterator end()
		{
			return _str + _size;
		}

		string& operator=(const string& str)
		{
			char* tmp = new char[str._capacity + 1];
			strcpy(tmp, str._str);
			delete[] _str;
			_str = tmp;
			_size = str._size;
			_capacity = str._capacity;
			return *this;
		}
		void reserve(int x)
		{
			if (_capacity < x)
			{
				char* tmp = new char[x + 1];
				strcpy(tmp, _str);
				delete[] _str;
				_str = tmp;
				_capacity = x;
			}
		}
		void swap(string& str)
		{
			std::swap(_str, str._str);
			std::swap(_size, str._size);
			std::swap(_capacity, str._capacity);
		}
		const char* c_str() const
		{
			return _str;
		}
		void clear()
		{

			_str[0] = '\0';
			_size = 0;
			_capacity = 0;
		}
		void insert(int index, const string& str)
		{
			int len = str._size;
			assert(index >= 0 && index < _size);
			if (_size + len >= _capacity)
			{
				reserve(_capacity + len);
			}
			for (int i = _size - 1; i >= index; i -- )
			{
				_str[i + len] = _str[i];
			}
			for (int j = 0, i = index; j < str._size; j ++ ,i ++ )
			{
				_str[i] = str._str[j];
			}
			_size += len;
		}
		void insert(int index, char ch)
		{
			assert(index >= 0 && index < _size);
			if (_size + 1 >= _capacity)
			{
				reserve(2 * _capacity);
				_capacity *= 2;
			}
			for (int i = _size - 1; i >= index; i -- )
			{
				_str[i + 1] = _str[i];
			}
			_str[index] = ch;
			_size ++ ;

		}
		void append(const string& str)
		{
			int len = str._size;
			if (len + _size > _capacity)
			{
				reserve(len + _size);
				_capacity = len * _size;
			}
			int end = _size;
			for (int i = 0; i < str._size; i ++ ,end ++ )
			{
				_str[end] = str._str[i];
			}
			_size += len;
		}
		string& operator+=(const string& str)
		{
			append(str);
			return *this;
		}
		void push_back(const char ch)
		{
			if (_size + 1 >= _capacity)
			{
				reserve(2 * _capacity);
			}
			_capacity *= 2;
			_str[_size] = ch;
			_size ++ ;
		}
		int size() const
		{
			return _size;
		}
		int capacity() const
		{
			return _capacity;
		}
		bool empty() const
		{
			return _size == 0;
		}
		void resize(int n, char ch = '\0')
		{
			if (n < _size)
			{
				for (int i = n; i < _size; i ++ )
				{
					_str[i] = '\0';
				}
			}
			else if (n + 1 < _capacity)
			{
				for (int i = _size; i < n; i ++ )
				{
					_str[i] = ch;
				}
			}
			else
			{
				reserve(n);
			}
		}
		char& operator[](size_t index)
		{
			assert(index < _size);
			return _str[index];
		}
		const char& operator[](size_t index)const
		{
			assert(index < _size);
			return _str[index];
		}
		bool operator==(const string& str)
		{
			int ret = strcmp(_str, str.c_str());
			return ret == 0;
		}
		bool operator!=(const string& str)
		{
			return !(*this == str);
		}
		bool operator>(const string& str)
		{
			int ret = strcmp(_str, str.c_str());
			return ret > 0;
		}
		bool operator<(const string& str)
		{
			int ret = strcmp(_str, str.c_str());
			return ret < 0;
		}
		bool operator<=(const string& str)
		{
			return *this < str || *this == str;
		}
		bool operator>=(const string& str)
		{
			return *this > str || *this == str;
		}
		int find (char c, size_t pos = 0) const
		{
			assert(pos < _size);
			for (int i = pos; i < _size; i ++ )
			{
				if (_str[i] == c) return i;
			}
			return npos;
		}
		int find (const char* s, size_t pos = 0) const
		{
			char* p = strstr(_str + pos, s);
			if (p != nullptr)
			{
				return p - _str;
			}
			return npos;
		}
		string& erase (size_t pos = 0, size_t len = npos)
		{
			assert(pos < _size);
			if (len == npos || len >= _size - pos)
			{
				_str[pos] = '\0';
				_size = pos;
			}
			else
			{
				int i = 0;
				for (i = pos + len; i < _size; i ++ )
				{
					_str[i - len] = _str[i];
				}
				_str[i] = '\0';
				_size -= len;
			}
			return *this;
		}
		friend ostream& operator<<(ostream& out, const string& str);
		friend istream& operator>>(istream& in, string& str);
	private:
		char* _str; // string存的字符串
		size_t _size; // string中字符串的长度 
		size_t _capacity; // string的容量
		static const size_t npos = -1;
	};

	inline ostream& operator<<(ostream& out, const string& str)
	{
		int len = str._size;
		for (int i = 0; i < len; i ++ )
		{
			out << str._str[i];
		}
		return out;
	}
	inline istream& operator>>(istream& in, string& str)
	{
		str.clear();
		char ch = in.get();
		char buff[128];
		int i = 0;
		while (ch != ' ' && ch != '\n')
		{
			buff[i ++ ] = ch;
			if (i == 127)
			{
				buff[i] = '\0';
				str += buff;
				i = 0;
			}
			ch = in.get();
		}

		if (i != 0)
		{
			buff[i] = '\0';
			str += buff;
		}
		return in;
	}
}

谢谢大家! 

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

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

相关文章

电脑回收站恢复,3个靠谱方法(2024版)

“想问问大家&#xff0c;回收站里丢失的文件还能恢复吗&#xff1f;我一不小心就把电脑回收站里的重要数据丢失了&#xff0c;现在不知道怎么操作才能恢复它了。希望大家帮帮我。” 在日常使用电脑的过程中&#xff0c;回收站是我们经常打交道的一个功能&#xff0c;它能帮助我…

【Python创建专属二维码】

1、在PyCharm | Settings | Python Interpreter中添加PDL、PILLOW(注意解释器版本) 2、代码 from PIL import Image import qrcodedef main():# QRCode&#xff08;&#xff09;创建一个对象&#xff1a;qr qrcode.QRCode(version5, error_correctionqrcode.constants.ERROR_…

前端框架技术革新历程:从原生DOM操作、数据双向绑定到虚拟DOM等框架原理深度解析,Web开发与用户体验的共赢

前端的发展与前端框架的发展相辅相成&#xff0c;形成了相互驱动、共同演进的关系。前端技术的进步不仅催生了前端框架的产生&#xff0c;也为其发展提供了源源不断的动力。 前端的发展 前端&#xff0c;即Web前端&#xff0c;是指在创建Web应用程序或网站过程中负责用户界面…

Docker之注册中心的使用与操作

一、Docker注册中心与仓库 Reastry 可译为注册中心或注册服务器&#xff0c;是存放仓库的地方&#xff0c;一个注册中心往往有很多仓库。Docker默认的注册中心是Docker Hub&#xff0c;其可以通过浏览器访问&#xff0c;也可以使用docker search命令访问。 仓库是集中存放镜像…

[图解]软件开发中的糊涂用语-04-为什么要追究糊涂用语

0 00:00:00,030 --> 00:00:05,620 今天呢&#xff0c;我们来说一个为什么要追究糊涂用语的问题 1 00:00:06,310 --> 00:00:06,548 2 00:00:06,548 --> 00:00:11,077 大家知道我们前些天都发了好几个视频 3 00:00:11,077 --> 00:00:13,461 追究这个糊涂用语 4 00…

Python中capstone实现反汇编可执行文件

1、基本案例——disasm函数 capstone有非常简单的API&#xff0c;所以使用该框架编写工具非常简单。接下来&#xff0c;下面的代码实现的功能是反汇编一些X86二进制文件&#xff0c;并打印出其对应的汇编语句。 代码展示&#xff1a; from capstone import * #将capstone模块…

列车tcn网络mvb从站接收代码流程解析

TCN-列车通信网络概述 机车车辆通信网络&#xff08;TCN-列车通信网络&#xff09;的基本组件是在整个列车单元中提供数据通信的有线列车总线&#xff08;WTB&#xff09;和用于在车辆或固定连接车辆组&#xff08;组成&#xff09;内进行数据交换&#xff08;通信&#xff09…

免费https证书申请及部署教程

目前随着https访问的普及度逐渐提高&#xff0c;https证书的使用率也与日俱增&#xff0c;多数网站都会通过实现https来保障自身网站的数据传输安全&#xff0c;这时候就离不开SSL证书了&#xff0c;如何获取SSL证书&#xff0c;又如何将SSL证书部署在域名上&#xff0c;今天为…

外贸客户开发有用的软件

外贸客户开发过程中&#xff0c;选择合适的软件工具能够显著提升效率和效果。以下是一些对外贸客户开发非常有用的软件&#xff1a; CRM系统&#xff1a; Salesforce&#xff1a;全球领先的CRM平台&#xff0c;提供强大的客户关系管理、市场分析、销售自动化等功能&#xff0c;…

关于RS485通信失败的问题(忽视了使能引脚)

问题 如图&#xff0c;使用485进行串口通信时&#xff0c;程序一直卡在接收这句。 解决 检查串口引脚配置都没问题&#xff0c;因此怀疑是硬件的原因。 在RS485通信中&#xff0c;通常需要一个使能信号来控制半双工总线上的发送和接收状态&#xff0c;这个信号经常被标记为&…

ProbeManager:一款功能强大的入侵检测系统集中化管理工具

关于ProbeManager ProbeManager是一款功能强大的入侵检测系统集中化管理工具&#xff0c;该工具旨在简化检测探针的部署任务&#xff0c;并将其所有功能集中在一个地方。 一般来说&#xff0c;很多入侵检测系统&#xff08;IDS&#xff09;包括其软件及规则都不会定期更新&…

C++ | Leetcode C++题解之第43题字符串相乘

题目&#xff1a; 题解&#xff1a; class Solution { public:string multiply(string num1, string num2) {if (num1 "0" || num2 "0") {return "0";}int m num1.size(), n num2.size();auto ansArr vector<int>(m n);for (int i …

Java 网络编程之TCP(一):基于BIO

环境&#xff1a; jdk 17 IntelliJ IDEA 2023.1.1 (Ultimate Edition) Windows 10 专业版 22H2 TCP&#xff1a;面向连接的&#xff0c;可靠的数据传送协议 Java中的TCP网络编程&#xff0c;其实就是基于常用的BIO和NIO来实现的&#xff0c;本文先讨论BIO&#xff1b; BIO…

Pytorch 学习路程 - 1:入门

目录 下载Pytorch 入门尝试 几种常见的Tensor Scalar Vector Matrix AutoGrad机制 线性回归尝试 使用hub模块 Pytorch是重要的人工智能深度学习框架。既然已经点进来&#xff0c;我们就详细的介绍一下啥是Pytorch PyTorch 希望将其代替 Numpy 来利用 GPUs 的威力&…

STM32F103ZET6 封装 LQFP-144 ST意法 单片机芯片

STM32F103ZET6 是意法半导体&#xff08;STMicroelectronics&#xff09;生产的一款基于 ARM Cortex-M3 内核的 32 位微控制器。它具有高性能、低功耗的特点&#xff0c;广泛应用于各种嵌入式系统和工业应用中。STM32F103ZET6 的主要特点如下&#xff1a; 内核&#xff1a;ARM…

【每日力扣】41. 缺失的第一个正数 238. 除自身以外数组的乘积 189. 轮转数组

&#x1f525; 个人主页: 黑洞晓威 &#x1f600;你不必等到非常厉害&#xff0c;才敢开始&#xff0c;你需要开始&#xff0c;才会变的非常厉害 41. 缺失的第一个正数 给你一个未排序的整数数组 nums &#xff0c;请你找出其中没有出现的最小的正整数。 请你实现时间复杂度为…

一个 Java 项目最多定义多少个线程池比较合理,有哪些限制因素需要考量?

在Java项目中&#xff0c;线程池是一种重要的并发机制&#xff0c;用于管理和执行多线程任务。然而&#xff0c;线程池的设计需要谨慎考虑&#xff0c;以确保系统的稳定性、性能和资源利用率。在决定一个Java项目中最多可以定义多少个线程池时&#xff0c;需要综合考虑多种因素…

IPRally巧用Google Kubernetes Engine和Ray改善AI

专利检索平台提供商 IPRally 正在快速发展&#xff0c;为全球企业、知识产权律师事务所以及多个国家专利和商标局提供服务。随着公司的发展&#xff0c;其技术需求也在不断增长。它继续训练模型以提高准确性&#xff0c;每周添加 200,000 条可供客户访问的可搜索记录&#xff0…

AI大模型探索之路-资料篇:大模型开发相关地址信息收藏

文章目录 前言一、OpenAI大模型二、LangChain开发框架三、RAGA评估框架四、GLM大模型五、搜索服务1. Tavily Search API 六、文本LLM大模型七、多模态LLM模型八、模型排行榜1.大模型评测体系&#xff08;司南OpenCompass&#xff09;2.大模型排行榜&#xff08;DataLearner AI&…

基于SSM的在线家教管理系统(含源码+sql+视频导入教程)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 基于SSM的在线家教管理系统1拥有三种角色 管理员&#xff1a;学生管理、老师管理、发布管理、留言管理、回复管理、订单管理等教师&#xff1a;我的订单、我的关注、查看回复留言、登录注…