【C++】-string类的模拟实现

news2024/9/21 12:27:39

💖作者:小树苗渴望变成参天大树🎈
🎉作者宣言:认真写好每一篇博客💤
🎊作者gitee:gitee✨
💞作者专栏:C语言,数据结构初阶,Linux,C++ 动态规划算法\🎄
请添加图片描述
如 果 你 喜 欢 作 者 的 文 章 ,就 给 作 者 点 点 关 注 吧!

文章目录

  • 前言


前言

大家好,今天带来的是string类的模拟实现,由于类的实现内容非常多,不好一个一个给大家介绍,所以我直接放源码,大家自己学习,不理解的评论区留言


模拟实现:
string.h

#pragma once
#include<string.h>
#include<iostream>
#include<assert.h>
using namespace std;

namespace xdh//先弄一个命名空间域,防止和库里面的冲突
{
	class string
	{
	public:
		//==========构造函数=============
		//写一个经典的构造函数
		/*string(const char* str)
			:_str(new char[strlen(str)])
			,_size(strlen(str))
			,_capacity(strlen(str))
		{
			strcpy(_str, str);
		}*/

		//无参构造器
	/*	string()
			:_str(new char[1])
			, _size(0)
			,_capacity(0)
		{
			_str[0] ='\0';
		}*/

		//合并构造器
		string(const char* str = "")
		{
			_size = strlen(str);
			_capacity = strlen(str);
			_str = new char[strlen(str)+1];
			//strcpy(_str,str);//这个可以不用替换成memcpy因为传进来本来就是字符串,以\0结尾的
			memcpy(_str, str, _size + 1);//strcpy默认拷贝到\0结束,而memcpy需要手动进行拷贝
			
		}

		//==========swap函数的实现==========
		void swap(string& s)
		{
			std::swap(_str,s._str);
			std::swap(_size, s._size);
			std::swap(_capacity, s._capacity);
		}
		//=============拷贝构造函数==========
		string(const string& s)
		{
			int len = strlen(s.c_str());
			
			_str = new char[len + 1];
			_size = len + 1;
			_capacity = _size;
			for (int i = 0; i <len; i++)
			{
				_str[i] = s[i];
			}
			_str[len] = '\0';
		}


		//字符串的大小
		size_t size() const
		{
			return _size;
		}

		//字符串的容量
		size_t capacity() const
		{
			return _capacity;
		}


		//转成指针
		const char* c_str() const
		{
			return _str;
		}
		//operator[]的重载
		char& operator[] (size_t pos)//具有读写功能
		{
			assert(pos < _size);
			return _str[pos];
		}
		const char& operator[] (size_t pos) const//只具有读功能
		{
			assert(pos < _size);
			return _str[pos];
		}

		//=================迭代器的实现(类似于指针)===============
		typedef char* iterator;
		typedef const char* const_iterator;
		typedef  char* reverse_iterator;
		typedef const char* const_reverse_iterator;

		iterator begin()
		{
			return _str;
		}

		iterator end()
		{
			return _str+_size;
		}

		const_iterator cbegin()const
		{
			return _str;
		}

		const_iterator cend()const
		{
			return _str + _size;
		}

		reverse_iterator rbegin()
		{
			return _str + _size;
		}
		reverse_iterator rend()
		{
			return _str;
		}
		const_reverse_iterator crbegin() const
		{
			return _str + _size;
		}
		const_reverse_iterator crend() const
		{
			
			return _str;
		}

		//reverve扩容函数的实现
		void reserve(size_t n = 0)
		{
			char* tmp = new char[n+1];
			//strcpy(tmp, _str);使用这个拷贝到中间字符就廷下来了,后面的拷贝不到了
			memcpy(tmp, _str, _size+1);
			delete[] _str;
			_str = tmp;
			_capacity = n;
		}

		//=========resize函数的实现
		void resize(size_t n, char c='\0')
		{
			if (n < _size)
			{
				_str[n] = '\0';
				_size = n;
			}
			else
			{
				reserve(n);
				for (int i = _size; i < n; i++)
				{
					_str[i] = c;
				}
				_str[n-1] = '\0';
				_size = n;
			}
		}
		//==========push_back的实现=========(实现经典的常用的)
		void push_back(char c)
		{
			if (_size == _capacity)
			{
				reserve(_capacity==0?4:_capacity*2);
			}
			
			_str[_size] = c;
			++_size;
			_str[_size] = '\0';
		}
		//==========append的实现=-==========(实现经典的常用的)
		void append(const char* s)
		{
			int len = strlen(s);
			if (_size + len > _capacity)
			{
				reserve(_size + len);
			}
		/*	for (int i = 0; i <=len; i++)
			{
				_str[_size +i] = s[i];
			}*/
			//strcpy(_str+ len, s);这个也可以不用换,传进来的字符串,为了保持一致性,也替换一下
			memcpy(_str + _size, s, len+1);
			_size += len+1;
		}

		
		//==========opeartor+=函数=========(复用前面的push_back和append)
		string& operator+= (const char* s)
		{
			append(s);
			return *this;
		}
		string& operator+= (char c)
		{
			push_back(c);
			return *this;
		}

		//==========insert函数的实现=============
		string& insert(size_t pos, const char* s) //(从pos的位置插入一个字符串)
		{
			assert(pos <= _size);
			int len = strlen(s);
			if (_size + len > _capacity)
			{
				reserve(_size + len);
			}
			size_t end = _size;
			while (pos <= end && end != npos)//当pos为0的时候,循环就退出不了,但pos减到-1的时候就当成了一个很大的数,所以再加一个条件判断
			{
				_str[end + len] = _str[end];
				end--;
			}
			for (int i = 0; i <len; i++)
			{
				_str[pos++] = s[i];
			}
			_size += len;
			return *this;

		}
		string& insert(size_t pos, size_t n, char c)//(从pos位置)
		{
			assert(pos <= _size);
			if (_size + n > _capacity)
			{
				reserve(_size + n);
			}
			//挪动数据
			size_t end = _size;
			while (pos <= end&&end!=npos)//当pos为0的时候,循环就退出不了,但pos减到-1的时候就当成了一个很大的数,所以再加一个条件判断
			{
				_str[end + n] = _str[end];
				end--;
			}

			//放数据
			for (int i = 0; i < n; i++)
			{
				_str[pos++] = c;
			}
			_size += n;
			return *this;

		}
		//==========erase函数的实现==============(从pos位置删除len长度的字符串)
		string& erase(size_t pos = 0, size_t len = npos)
		{
			assert(pos <= _size);
			if (pos + len >=_size)
			{
				_str[pos] = '\0';
				_size = pos;
				_str[_size] = '\0';
			}
			else
			{
				//覆盖数据
				size_t end = pos+len;
				while (end <= _size)
				{
					_str[pos++] = _str[end++];
				}
				_size -= len;
			}
			
			return *this;
		}

		//==========find的函数的实现=============
		size_t find(const char* s, size_t pos = 0) const//从pos位置开始查找一个子串
		{
			assert(pos <= _size);
			const char* ptr = strstr(_str+pos, s);
			if (ptr)
			{
				return ptr - _str;
			}
			else
			{
				return npos;
			}
		}
		size_t find(char c, size_t pos = 0) const//从pos位置开始查找一个字符
		{
			assert(pos <= _size);
			for (int i = pos; i < _size; i++)
			{
				if (_str[i] == c)
				{
					return i;
				}
			}
			return npos;

		}

		//=============substr函数的实现//获取子串
		string substr(size_t pos = 0, size_t len = npos)//从pos位置查找长度为len的子串
		{
			assert(pos <= _size);
			
			if (len==npos||pos + len > _size)
			{
				char* tmp = new char[_size - pos+1];
				//strcpy(tmp, _str + pos);
				memcpy(tmp, _str + pos, len + 1);
				string Tmp(tmp);
				return tmp;
			}
			else
			{
				char* tmp = new char[len + 1];
				int j = 0;
				for (int i = pos; i < pos + len; i++)
				{
					tmp[j++] = _str[i];
				}				
				tmp[j] = '\0';
				string Tmp(tmp);
				return tmp;
			}
		}
		//============operator=函数============
		/*string& operator=(const string& s)
		{
			int len = strlen(s.c_str());
			_str = new char[len + 1];
			_size = len + 1;
			_capacity = _size;
			for (int i = 0; i < len; i++)
			{
				_str[i] = s[i];
			}
			_str[len] = '\0';
			return *this;
		}
		string& operator= (const char* s)
		{
			int len = strlen(s);
			_str = new char[len + 1];
			_size = len + 1;
			_capacity = _size;
			for (int i = 0; i < len; i++)
			{
				_str[i] = s[i];
			}
			_str[len] = '\0';
			return *this;
		}*/
		//string& operator=(const string& s)
		//{
		//	string tmp(s);
		//	swap(tmp);
		//	return *this;
		//}

		string& operator=(string s)
		{
			
			swap(s);
			return *this;
		}

		//============clear函数的实现=======
		void clear()
		{
			_size = 0;
			_str[_size] = '\0';
		}
		//=============析构函数===========
		~string()
		{
			delete[] _str;
			_str = nullptr;
			_size = _capacity = 0;
		}


		//===============字符串比较函数================
		bool operator<(const string& s)const
		{

			int ret=memcmp(_str, s._str, _size > s._size ? s._size : _size); 
			if (ret == 0)
			{
				if (s._size > _size)
				{
					return true;
				}
			}
			return ret<0;
		}
		bool operator==(const string& s)const
		{
			return _size == s._size && memcmp(_str, s._str, _size)==0;
		}

		bool operator<=(const string& s)const
		{
			return (*this) < s || (*this) == s;
		}
		bool operator>(const string& s)const
		{
			return !((*this) <= s);
		}
		bool operator>=(const string& s)const
		{
			return !((*this) < s);
		}
		bool operator!=(const string& s)const
		{
			return !((*this) == s);
		}

		static size_t npos;

		
		friend  ostream& operator<<(ostream& cout, const string& s);
		friend  istream& operator>>(istream& cin, string& s);

	private:
		char* _str;
		size_t _size;
		size_t _capacity;
	};
	size_t string::npos = -1;

	ostream& operator<<(ostream& cout, const string& s)
	{
		//cout << s.c_str();//这个大部分情况是可以的,但是中间有\0的情况不行,那么之前的strcpy函数都需要换,
		//因为strcpy遇到\0就会停止,需要使用memcpy,按照字节赋值,string不是看\0结束的,而是看size结束的,strlen不需要换,他传进去就是字符串
		for (int i = 0; i < s.size(); i++)
		{
			cout << s[i];
		}
		cout << endl;
		return cout;
	}
	istream& operator>>(istream& cin, string& s)
	{
		s.clear();
		char ch = cin.get();
		const size_t N = 32;
		char buff[N];//防止多次扩容,带来的消耗
		int i = 0;
		while (ch != ' ' && ch != '\n')
		{
			buff[i++] = ch;
			if (i == N - 1)
			{
				buff[i] = '\0';
				s += buff;
				i = 0;
			}
			ch = cin.get();
		}
		buff[i] = '\0';
			s += buff;
	
		return cin;
	}
}

Test.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include"string.h"
void test_string1()
{
	xdh::string s1("hello world");
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	cout << "非const对象循环遍历:";
	for (int i = 0; i < s1.size(); i++)
	{
		s1[i]+=1;
		cout << s1[i] << " ";
	}
	cout << endl;


	const xdh::string s2("hello C++");
	cout << s2.size() << endl;
	cout << s2.capacity() << endl;
	cout << "const对象循环遍历:";
	for (int i = 0; i < s2.size(); i++)
	{
		cout << s2[i] << " ";
	}
	cout << endl;


	//=====迭代器的测试=====

	//正向非const迭代器
	xdh::string s3("hello linux");
	cout << "正向非const迭代器:";
	xdh::string::iterator it = s3.begin();
	while (it != s3.end())
	{
		cout << *it<< " ";
		it++;
	}
	cout << endl;

	//正向const迭代器
	cout << "正向const迭代器:";
	const xdh::string s4("hello java");
	xdh::string::const_iterator cit = s4.cbegin();
	while (cit != s4.cend())
	{
		cout << (*cit) << " ";
		cit++;
	}
	cout << endl;

	反向非const迭代器
	xdh::string s5("hello linux");
	cout << "反向非const迭代器:";
	xdh::string::reverse_iterator rit = s5.rbegin();
	while (rit != s5.rend())
	{
		cout << (*rit) << " ";
		rit--;
	}
	cout << endl;

	反向const迭代器
	cout << "反向const迭代器:";
	const xdh::string s6("hello java");
	xdh::string::const_reverse_iterator crit = s6.crbegin();
	while (crit != s6.crend())
	{
		cout << (*crit) << " ";
		crit--;
	}
	cout << endl;

	//=======范围for=========(是基于迭代器的基础上)
	cout << "范围for:";
	xdh::string s7("hello sql");
	for (char ch : s7)
	{
		cout << ch << " ";
	}
	cout << endl;

 }
void test_string2()//测试push_back和append函数功能的
{
	xdh::string s1("");
	s1.push_back('n');
	cout << s1.c_str() << endl;

	xdh::string s2("hello world");
	s2.append("nihao");
	cout << s2.c_str() << endl;


	xdh::string s3("hello world");
	s3+='n';
	cout << s3.c_str() << endl;

	xdh::string s4("hello world");
	s4+="nihaoma";
	cout << s4.c_str() << endl;
}


void test_string3()//测试insert和erase函数功能的
{
	//再pos位置插入n个字符
	xdh::string s1("hello world");
	s1.insert(0, 13, '#');
	cout << s1.c_str() << endl;

	xdh::string s2("hello world");
	s2.insert(5, 13, '#');
	cout << s2.c_str() << endl;
	

	//再pos位置插入一个字符串
	xdh::string s3("hello world");
	s3.insert(0, "###");
	cout << s3.c_str() << endl;

	xdh::string s4("hello world");
	s4.insert(5,"###");
	cout << s4.c_str() << endl;


	//再pos位置删除n个字符
	xdh::string s5("hello world");
	s5.erase(5,3);
	cout << s5.c_str() << endl;

	xdh::string s6("hello world");
	s6.erase(0,3);
	cout << s6.c_str() << endl;


	xdh::string s7("hello world");
	s7.erase(11, 3);
	cout << s7.c_str() << endl;
}


void test_string4()//测试find和substr函数功能的
{
	xdh::string url = "ftp://www.baidu.com/?tn=65081411_1_oem_dg";

	size_t pos1 = url.find("://");
	if (pos1 != xdh::string::npos)
	{
		xdh::string protocol = url.substr(0, pos1);
		cout << protocol.c_str() << endl;
	}

	size_t pos2 = url.find('/', pos1 + 3);
	if (pos2 != xdh::string::npos)
	{
		xdh::string domain = url.substr(pos1 + 3, pos2 - (pos1 + 3));
		xdh::string uri = url.substr(pos2 + 1);

		cout << domain.c_str() << endl;
		cout << uri.c_str() << endl;
	}
}

void test_string5()//测试拷贝构造和赋值运算符
{
	const xdh::string s1("xudonghui");
	const xdh::string s2(s1);
	cout << s1.c_str() << endl;
	cout << s2.c_str() << endl;


	xdh::string s3("xudonghui");
	xdh::string s4 = s3;
	cout << s3.c_str() << endl;
	cout << s4.c_str() << endl;

	xdh::string s5("xu");
	xdh::string s6("niadia");
	s5 = s6;
	cout << s5.c_str() << endl;
	cout << s6.c_str() << endl;

	xdh::string s7("xu");
	s7 = "nihao";
	;
	cout << s7.c_str() << endl;
}

void test_string6()//测试输入输出函数
{
	xdh::string s1("hello"), s2;
	cin >> s1 >> s2;
	cout << s1 << s2;
}

void test_string7()
{
	xdh::string s1("hello world");
	s1.resize(20,'9');
	cout << s1;
}

void test_string8()
{
	xdh::string s1("awqdq ");
	xdh::string s2("hello");
	cout << (s1 < s2) << endl;
}

void test_string9()
{
	xdh::string s1("awqdq ");
	xdh::string s2("hello");
	s1 = s2;
	cout << s1 << s2;
}
int main()
{
	/*test_string1();
	cout << endl;
	test_string2();
	cout << endl;

	test_string3();
	cout << endl;

	test_string4();
	cout << endl;

	test_string5();
	cout << endl;*/

	test_string9();

	return 0;
}

大家自己看着实现一下
请添加图片描述

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

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

相关文章

抖音seo源码开发部署技术分享(一)

目录 开发概述 自研开发者介绍 开发要求&#xff1a; 技术开发布局 源码部署及搭建分享 部署环境搭建 代码开发示例 请求样例 响应样例&#xff1a; 代码展示样例 开发概述 开放平台基于开发者诉求和相关平台规则&#xff0c;提供了两种开放模式&#xff1a;能力开放…

前端Vue自定义顶部导航栏navBar 导航栏搜索框searchBar 导航栏右侧菜单按钮button

前端Vue自定义顶部导航栏navBar 导航栏搜索框searchBar 导航栏右侧菜单按钮button&#xff0c;下载完整代码请访问uni-app插件市场地址&#xff1a;https://ext.dcloud.net.cn/plugin?id13342 效果图如下: # cc-headerSearch #### 使用方法 使用方法 <!-- icon: 右侧菜单…

OpenCV在一个图像上画一个空心绿色的圆和一个实心红色的圆

/*** void cvCircle( CvArr* img, CvPoint center, int radius, CvScalar color, int thickness=1, int line_type=8, int shift=0 );* Opencv画点 其实画的是小圆圈* img:图像。* center:圆心坐标。* radius:圆形的半径。* color:线条的颜色。* thickness:如果是正数,表…

vue筛选框封装

点击对默认查询条件之外的条件进行 增加或删除 在使用的组件或标签加入:filtrateList"filtrateList"传入条件查询数组 当前demo写在xk-page中,就以xk-page组件为例 <xk-upage :filtrateList"filtrateList" :queryArr"queryArr"></xk-…

java项目之母婴用品网站(ssm+mysql+jsp)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于ssm的母婴用品网站。 开发环境&#xff1a; 后端&#xff1a; 开发语言&#xff1a;Java 框架&#xff1a;ssm&#xff0c;mybatis JDK版本&am…

EasyCVR非按需定时快照功能的设计与实现方法

EasyCVR基于云边端一体化架构&#xff0c;部署轻快、功能灵活&#xff0c;平台可支持多协议、多类型设备接入&#xff0c;包括&#xff1a;国标GB28181、RTMP、RTSP/Onvif、海康Ehome、海康SDK、大华SDK、宇视SDK等。在视频能力上&#xff0c;可实现视频直播、录像、回放、检索…

Gradio库中的Model3D模块:实时上传和展示3D模型

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

F#奇妙游(9):来一点点画图

F#绘图 如果Python没有Matplotlib&#xff0c;R没有ggplot&#xff0c;Matplab没有plot函数……就像阿珍爱上了阿强&#xff0c;能画图的脚本才是好脚本。当然&#xff0c;F#有画图包&#xff0c;但是F#在数据处理中的地位就像下面&#xff0c;这也是我们没办法的。 ScottPl…

分析openGauss包内集合类型的实现方法

前言 Oracle中集合类型覆盖了Postgresql数组的功能&#xff0c;在Oracle用户中时非常常用的。 尤其是包内定义的集合类型&#xff0c;在SPEC定义后即可直接使用&#xff0c;scope也只在包在生效&#xff0c;使用非常灵活。 开源PG因为有数组没有实现这部分语法&#xff0c;下…

超级广场效果的耳机放大器音响电路设计

用头戴式耳机&#xff0c;尤其是小型耳机听音乐&#xff0c;总感到音乐味不够足&#xff0c;在低频段的效果更差。因此用本机增强耳机的低频特性&#xff0c;并采用立体声反相合成的办法&#xff0c;加上内藏简易矩阵环绕声电路&#xff0c;能获得强劲的低音和在较宽的范围内展…

Windows mingw64 最简易 安装配置

其实挺简单一件事 很多教程都搞复杂了 自己写一个 只需要两步 1. 下载压缩包并解压 2. 配置环境变量 (1). GitHub 下载地址 Releases niXman/mingw-builds-binaries GitHub 如果GitHub下载太慢可以来这里加速 或者用地址2 GitHub Proxy 代理加速 (ghproxy.com) (2). 下…

-Xss1m / -XX:ThreadStackSize=512k

-Xss / -XX:ThreadStackSize指定线程最大栈空间jdk1.4里默认的栈大小是256KBjdk1.5里默认的栈大小为1M配置JVM启动参数&#xff1a;-Xmx20m -Xms20m -Xss1m -XX:PrintCommandLineFlags-XX:ConcGCThreads3 -XX:G1ConcRefinementThreads13 -XX:GCDrainStackTargetSize64 -XX:Init…

学习grpc

Grpc简介&#xff1a; gRPC是一个高性能、通用的开源RPC框架&#xff0c;其由Google主要面向移动应用开发并基于HTTP/2协议标准而设计&#xff0c;基于ProtoBuf(Protocol Buffers)序列化协议开发&#xff0c;且支持众多开发语言&#xff0c;能够基于语言自动生成客户端和服务端…

软负载Nginx详细配置及使用案例

Nginx使用与配置 什么是nginx Nginx 是一个高性能的HTTP和反向代理服务&#xff0c;也是一个IMAP/POP3/SMTP服务。 处理响应请求很快高并发连接低的内存消耗具有很高的可靠性高扩展性热部署 master 管理进程与 worker 工作进程的分离设计&#xff0c;使得 Nginx 具有热部署的…

Quartz表达式在线生成器

Quartz Cron表达式生成器 - devTest.run Quartz是一款高效的定时任务调度框架&#xff0c;由于其稳定性&#xff0c;高可用性和灵活性&#xff0c;Quartz已成为Java企业级开发中应用最为广泛的定时任务调度框架之一。 Quartz的主要特点包括&#xff1a;可配置的作业触发器&…

学C的第二十五天【指针的进阶】

相关代码gitee自取&#xff1a;C语言学习日记: 加油努力 (gitee.com) 接上期&#xff1a; 学C的第二十四天【练习&#xff1a;1. 打印菱形&#xff1b;2. 打印自幂数&#xff1b;3. 求Snaaa..n项之和&#xff1b;4. 喝汽水问题&#xff1b;5. 调整数组使奇数位于偶数前面&…

第三章——处理数据

面向对象编程&#xff08;OOP&#xff09;的本质是设计并扩展自己的数据类型。设计自己的数据类型就是让类型与数据匹配。在创建自己的类型之前必须先了解C内置的类型。 内置的C类型分为两组&#xff1a;基本类型和复合类型 简单变量 程序通常都需要存储信息&#xff0c;为把…

git commit history导出

git log --after"2022-1-1" --dateshort --prettyformat:"%H","%an","%ae","%ad","%s" --shortstat --no-merges再简洁一点 git log --after"2022-4-1" --dateshort --prettyformat:%H,%an,%ae,%ad,%…

Network Neuroscience:整个生命周期的功能连接体指纹

导读 随着年龄的增长&#xff0c;人脑功能结构发生了系统性的变化。然而&#xff0c;功能连接(FC)作为一种检测独特“连接体指纹”的强大特征&#xff0c;使个体能够在同龄人中被识别出来。虽然已在年轻人样本中观察到这种指纹&#xff0c;但该方法在整个生命周期内的可靠性尚…