【C++】模拟实现string

news2024/11/26 17:29:35

 

目录

🌞专栏导读

🌛定义string类

 🌛构造函数

🌛拷贝构造函数

🌛赋值函数

🌛析构函数 

🌛[]操作符重载 

🌛c_str、size、capacity函数 

🌛比较运算符重载 

 🌛resize与reserve函数

🌛push_back、append函数 

🌛insert函数 

🌛erase函数

🌛find函数

 🌛swap函数

🌛clean函数

 🌛迭代器

🌛>> 与 << 重载


🌞专栏导读

🌟作者简介:日出等日落,在读本科生一枚,致力于 C/C++、Linux 学习。

🌟本文收录于 C++系列,本专栏主要内容为 C++ 初阶、C++ 进阶、STL 详解等,持续更新!

🌟相关专栏推荐:C语言系列 、Linux系列 、数据结构与算法

本章我们将模拟实现string,但不一定非要与库中完全相同。我们将其中重要的、常用的接口进行模拟实现,旨在加深string类的学习与记忆。 

🌛定义string类

为了区别于标准库中的string,这里使用自己的命名空间,在自己的命名空间模拟实现string

string包含这三个基本成员

  • char* _str 字符数组;
  • size_t _size 有效字符大小;
  • size_t _capacity 容量;

 此外还需声明一个static成员nposnpos为将来实现的某些成员函数的缺省值,值位-1

namespace yxb
{
	class string
	{
	public:

    private:
		char* _str;
		size_t _capacity;
		size_t _size;
        
        //类中声明
		static const size_t npos;
	};

        //类外定义
    const size_t string::npos = -1;
}

 🌛构造函数

//构造函数
	string(const char* str = "")  //使用缺省值
		:_size(strlen(str))
	{
		_capacity = _size == 0 ? 3 : _size;  //_capacity初始值不能为0
		_str = new char[_capacity + 1];  //为'\0'预留位置
		strcpy(_str, str);
	}

注意

  • _capacity的值不能初始化为0,因为扩容时可能出现0*n=0的情况。

🌛拷贝构造函数

拷贝构造虽然编译器会自动实现,但是自动实现的拷贝构造为浅拷贝,对于string类中,成员变量会申请资源的情况,浅拷贝是行不通的,所以需要我们自己实现。

//拷贝构造s3(s2)
		string(const string& s)
			:_size(s._size)
			,_capacity(s._capacity)
		{
			_str = new char[s._capacity + 1];
			strcpy(_str, s._str);
		}

🌛赋值函数

	//s1 = s3   s1 = s1
		string& operator=(const string& s)
		{
			if (this != &s)
			{
				char* tmp = new char[s._capacity + 1];
				strcpy(tmp,s._str);
				delete[] _str;
				_str = tmp;
				_size = s._size;
				_capacity = s._capacity;
			}
			return *this;
		}

🌛析构函数 

~string()
		{
			delete[] _str;
			_str = nullptr;
			_capacity = _size = 0; 
		}

🌛[]操作符重载 

注意应对const对象与非const对象须实现不同的重载函数。

        char& operator[](size_t pos)
		{
			assert(pos < _size);
			return _str[pos];
		}


		const char& operator[](size_t pos)const
		{
			assert(pos < _size);
			return _str[pos];
		}

🌛c_str、size、capacity函数 

  • c_str:返回C风格的字符串。
  • size:返回_size;
  • capacity:返回_capacity;
	const char* c_str()
	{
		return _str;
	}
	
	size_t size() const
	{
		return _size;
	}

	size_t capacity() const
	{
		return _capacity;
	}

🌛比较运算符重载 

	//比较运算符重载
	bool operator>(const string& s) const
	{
		return strcmp(_str, s._str) > 0;
	}

	bool operator==(const string& s) const
	{
		return strcmp(_str, s._str) == 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);
	}

 🌛resize与reserve函数

  • resize:扩容并初始化;
  • reserve:只扩容;
//扩容
		void reverse(size_t n)
		{
			if (n > _capacity)
			{
				char* tmp = new char[n + 1];
				strcpy(tmp, _str);
				delete[] _str;
				_str = tmp;
				_capacity = n;
			}
		}

		//扩容+初始化
		void resize(size_t n, char ch = '\0')
		{
			if (n <= _size)
			{
				//删除数据,保留前n个
				_size = n;
				_str[_size] = '\0';
			}
			else
			{
				if (n > _capacity)
				{
					reverse(n);
				}
				size_t i = _size;
				while (i < n)
				{
					_str[i++] = ch;
				}
				_size = n;
				_str[_size] = '\0';
			}
		}

🌛push_back、append函数 

  • push_back:尾插一个字符;
  • append:尾插一个字符串;
  • +=:尾插一个字符或字符串;

		void push_back(char ch)
		{
			if (_size + 1 > _capacity)
			{
				reverse(_capacity * 2);
			}
			_str[_size] = ch;
			_size++;
			_str[_size] = '\0';
		}

		void append(const char* str)
		{
			size_t len = strlen(str);
			if (_size + len > _capacity)
			{
				reverse(_size + len);
			}
			strcpy(_str + _size, str);
			_size += len;
		}

		string& operator+=(char ch)
		{
			push_back(ch);
			return *this;
		}

		string& operator+=(const char* str)
		{
			append(str);
			return *this;
		}

🌛insert函数 

  • insert:在pos位置插入一个字符或字符串;
	void insert(size_t pos, char ch)
		{
			assert(pos <= _size);
			if (_size + 1 > _capacity)
			{
				reverse(2 * _capacity);
			}
			size_t end = _size + 1;
			while (pos < end)
			{
				_str[end] = _str[end - 1];
				end--;
			}
			_str[pos] = ch;
			_size++;
		}

		void insert(size_t pos, const char* str)
		{
			assert(pos <= _size);
			size_t len = strlen(str);
			
			if (_size + len > _capacity)
			{
				reverse(_size + len);
			}
			
			//挪动数据
			size_t end = _size + len;
			while ( end > pos +len-1 )
			{
				_str[end] = _str[end-len];
					end--;
			}
			//拷贝插入 
			strncpy(_str + pos, str, len);
			_size += len;
		}

🌛erase函数

  • erase:删除pos位置向后的n个字符;
	void erase(size_t pos, size_t len = npos)
		{
			if (len == npos || pos + len >= _size)
			{
				_str[pos] = '\0';
				_size = pos;
			}
			//0123456789
			else
			{
				strcpy(_str + pos, _str + pos + len);
				_size -= pos;
			}
		}

🌛find函数

  • find:从pos位置开始向后查找指定字符或字符串,并返回起始位置的下标。
	size_t find(char ch, size_t pos = npos)
	{
		assert(pos < _size);

		for (size_t i = pos; i < _size; ++i)
		{
			if (_str[i] == ch)
			{
				return i;
			}
		}
		return npos;
	}

	size_t find(const char* str, size_t pos = npos)
	{
		assert(pos < _size);

		char* p = strstr(_str, str);
		if (p == nullptr)
		{
			return npos;
		}
		else
		{
			return p - str;
		}
	}

 🌛swap函数

	void swap(string& s)
	{
		std::swap(_str, s._str);
		std::swap(_size, s._size);
		std::swap(_capacity, s._capacity);
	}

🌛clean函数

  • clean:清理数据;
	void clean()
	{
		_str[0] = '\0';
		_size = 0;
	}

 🌛迭代器

	//迭代器
	typedef char* iterator;
	typedef const char* const_iterator;

	iterator begin()
	{
		return _str;
	}

	iterator end()
	{
		return _str + _size;
	}

	const_iterator begin() const
	{
		return _str;
	}

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

🌛>> 与 << 重载

注意这两个函数须定义在类外

    ostream& operator<<(ostream& out, const string& str)
	{
		for (auto ch : str)
		{
			out << ch;
		}
		
		return out;
	}

	istream& operator>>(istream& in, string& str)
	{
		str.clean();

		char ch = in.get();
		char buff[128]; //避免因频繁扩容导致效率过低
		size_t i = 0;
		while (ch != ' ' && ch != '\n')
		{
			buff[i++] = ch;
			if (i == 127)
			{
				buff[127] = '\0';
				str += buff;
				i = 0;
			}
			ch = in.get();
		}

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

		return in;
	}

🌛完整代码

#pragma once
#include<assert.h>

namespace yxb
{
	class string
	{
	public:
		typedef char* iterator;
		typedef const char* const_iterator;

		iterator begin()
		{
			return _str;
		}
		iterator end()
		{
			return _str + _size;
		}
		const_iterator begin()const
		{
			return _str;
		}
		const_iterator end()const
		{
			return _str + _size;
		}
		/*string()
			:_str(new char[1])
			, _size(0)
			,_capacity(0)
		{
			_str[0] = '\0';
		}*/

		string(const char* str = "")
			:_size(strlen(str))
		{
			_capacity = _size == 0 ? 3 : _size;
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}

		//拷贝构造s3(s2)
		string(const string& s)
			:_size(s._size)
			,_capacity(s._capacity)
		{
			_str = new char[s._capacity + 1];
			strcpy(_str, s._str);
		}

		//s1 = s3   s1 = s1
		string& operator=(const string& s)
		{
			if (this != &s)
			{
				char* tmp = new char[s._capacity + 1];
				strcpy(tmp,s._str);
				delete[] _str;
				_str = tmp;
				_size = s._size;
				_capacity = s._capacity;
			}
			return *this;
		}

		~string()
		{
			delete[] _str;
			_str = nullptr;
			_capacity = _size = 0; 
		}

		const char* c_str()
		{
			return _str;
		}

		char& operator[](size_t pos)
		{
			assert(pos < _size);
			return _str[pos];
		}

		const char& operator[](size_t pos)const
		{
			assert(pos < _size);
			return _str[pos];
		}

		size_t size()const
		{
			return _size;
		}

		size_t capacity()const
		{
			return _capacity;
		}

		bool operator>(const string& s)const
		{
			return strcmp(_str, s._str) > 0;
		}
		bool operator==(const string& s)const
		{
			return strcmp(_str, s._str) == 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);
		}
		
		//扩容
		void reverse(size_t n)
		{
			if (n > _capacity)
			{
				char* tmp = new char[n + 1];
				strcpy(tmp, _str);
				delete[] _str;
				_str = tmp;
				_capacity = n;
			}
		}

		//扩容+初始化
		void resize(size_t n, char ch = '\0')
		{
			if (n <= _size)
			{
				//删除数据,保留前n个
				_size = n;
				_str[_size] = '\0';
			}
			else
			{
				if (n > _capacity)
				{
					reverse(n);
				}
				size_t i = _size;
				while (i < n)
				{
					_str[i++] = ch;
				}
				_size = n;
				_str[_size] = '\0';
			}
		}

		void push_back(char ch)
		{
			if (_size + 1 > _capacity)
			{
				reverse(_capacity * 2);
			}
			_str[_size] = ch;
			_size++;
			_str[_size] = '\0';
		}

		void append(const char* str)
		{
			size_t len = strlen(str);
			if (_size + len > _capacity)
			{
				reverse(_size + len);
			}
			strcpy(_str + _size, str);
			_size += len;
		}

		string& operator+=(char ch)
		{
			push_back(ch);
			return *this;
		}

		string& operator+=(const char* str)
		{
			append(str);
			return *this;
		}

		void insert(size_t pos, char ch)
		{
			assert(pos <= _size);
			if (_size + 1 > _capacity)
			{
				reverse(2 * _capacity);
			}
			size_t end = _size + 1;
			while (pos < end)
			{
				_str[end] = _str[end - 1];
				end--;
			}
			_str[pos] = ch;
			_size++;
		}

		void insert(size_t pos, const char* str)
		{
			assert(pos <= _size);
			size_t len = strlen(str);
			
			if (_size + len > _capacity)
			{
				reverse(_size + len);
			}
			
			//挪动数据
			size_t end = _size + len;
			while ( end > pos +len-1 )
			{
				_str[end] = _str[end-len];
					end--;
			}
			//拷贝插入 
			strncpy(_str + pos, str, len);
			_size += len;
		}

		void erase(size_t pos, size_t len = npos)
		{
			if (len == npos || pos + len >= _size)
			{
				_str[pos] = '\0';
				_size = pos;
			}
			//0123456789
			else
			{
				strcpy(_str + pos, _str + pos + len);
				_size -= pos;
			}
		}
		size_t find(char ch, size_t pos = npos)
		{
			assert(pos < _size);

			for (size_t i = pos; i < _size; ++i)
			{
				if (_str[i] == ch)
				{
					return i;
				}
			}
			return npos;
		}

		size_t find(const char* str, size_t pos = npos)
		{
			assert(pos < _size);

			char* p = strstr(_str, str);
			if (p == nullptr)
			{
				return npos;
			}
			else
			{
				return p - str;
			}
		}

		void swap(string& s)
		{
			std::swap(_str, s._str);
			std::swap(_size, s._size);
			std::swap(_capacity, s._capacity);
		}
		void clean()
		{
			_str[0] = '\0';
			_size = 0;
		}


	private:
		char* _str;
		size_t _capacity;
		size_t _size;

		static const size_t npos;
	};

	const size_t string::npos = -1;

	ostream& operator<<(ostream& out, const string& str)
	{
		for (auto ch : str)
		{
			out << ch;
		}

		return out;
	}

	istream& operator>>(istream& in, string& str)
	{
		str.clean();

		char ch = in.get();
		char buff[128]; //避免因频繁扩容导致效率过低
		size_t i = 0;
		while (ch != ' ' && ch != '\n')
		{
			buff[i++] = ch;
			if (i == 127)
			{
				buff[127] = '\0';
				str += buff;
				i = 0;
			}
			ch = in.get();
		}

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

		return in;
	}

	void test_string1()
	{	
		string s1;
		string s2("hello world");
		cout << s1.c_str() << endl;
		cout << s2.c_str() << endl;
		s2[0]++;
		cout << s2.c_str() << endl;

	}
	void test_string2()
	{
		string s1;
		string s2("hello world");
		cout << s1.c_str() << endl;
		cout << s2.c_str() << endl;
		s1 = s2;
		cout << s1.c_str() << endl;
		cout << s2.c_str() << endl;
	}
	void test_string3()
	{
		string s1;
		string s2("hello world");
		cout << s1.c_str() << endl;
		cout << s2.c_str() << endl;
		
		string::iterator it = s2.begin();
		while (it != s2.end())
		{
			cout << *it << endl;
			++it;
		}
	}
	void test_string4()
	{
		string s1;
		string s2("hello world");
		string s3("hello");

		cout << s1.c_str() << endl;
		cout << s2.c_str() << endl;
		cout << (s3 >= s2) << endl;
	}
	void test_string5()
	{
		string s1;
		string s2("hello world");
		s2.append("yyyyyy");
		cout << s2.c_str() << endl;
	}
	void test_string6()
	{
		string s1("hhh ");
		cout << s1.c_str() << endl;
		s1.resize(10, 'x');
		cout << s1.c_str() << endl;
		s1.resize(100, 'y');
		cout << s1.c_str() << endl;
	}
	void test_string7()
	{
		string s1("123456789");
		cout << s1.c_str() << endl;

		s1.insert(2, "wwww");
		cout << s1.c_str() << endl;

		s1.insert(0, "ss");
		cout << s1.c_str() << endl;

	}
	void test_string8()
	{
		string s1("123456789");
		cout << s1.c_str() << endl;

		s1.erase(4, 2);
		cout << s1.c_str() << endl;

	}

	void test_string9()
	{
		string s1;
		cin >> s1;
		cout << s1 << endl;
	}
}

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

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

相关文章

CuratorFramework接口的作用和使用

CuratorFramework接口是Apache Curator库中的核心接口之一&#xff0c;用于与ZooKeeper集群进行交互。它提供了一组丰富的方法和功能&#xff0c;用于简化与ZooKeeper的交互操作&#xff0c;包括创建、删除、读取和更新节点等。 CuratorFramework接口的主要作用是封装了底层与…

uni-app:实现列表单选功能

效果图&#xff1a; 核心解析&#xff1a; 一、 <view class"item_all" v-for"(item, index) in info" :key"index"><view classposition parameter-info text-over :classitem.checked?"checked_parameter":""…

【华秋推荐】物联网入门学习模块 ESP8266

随着全球信息技术的不断进步和普及&#xff0c;物联网成为当今备受关注的技术热点之一。通过物理和数字设备之间的连接来实现自动化和互联互通的网络。无线传感器、云计算和大数据分析等技术&#xff0c;物联网使设备能够相互交流和共享信息&#xff0c;实现智能化的自动化操作…

从k8s 的声明式API 到 GPT的 提示语

命令式 命令式有时也称为指令式&#xff0c;命令式的场景下&#xff0c;计算机只会机械的完成指定的命令操作&#xff0c;执行的结果就取决于执行的命令是否正确。GPT 之前的人工智能就是这种典型的命令式&#xff0c;通过不断的炼丹&#xff0c;告诉计算机要怎么做&#xff0…

真的能缓解焦虑和负面情绪的一个技巧——进度条

我之前博客——https://blog.csdn.net/qq_41517071/article/details/129793252 负面情绪原因 当代负面情绪无法及时下线&#xff0c;导致情绪出现帮倒忙的情况。此情况主要由两种原因导致&#xff1a;①无发泄出口。人类社会身不由己&#xff0c;无法找到合适的发泄出口。②…

【超细节】Vue3组件事件怎么声明,defineEmits与emit

目录 前言 一、基本语法 1. 子组件触发 2. 父组件监听 二、 事件参数 1. 传值 2. 接收值 三、 事件校验 四、注意事项 前言 组件事件是 Vue 组件之间进行通信的一种方式。它允许一个组件触发一个自定义事件&#xff0c;并且其他组件可以监听并响应这个事件。 一、基本…

1308. 方程的解(隔板法)

题目链接&#xff1a;https://www.acwing.com/activity/content/problem/content/1761/ 本题需要用高精度 Code #include <cstring> #include <iostream> #include <algorithm>using namespace std;const int N 150;int k, x; int f[1000][100][N];int qm…

Docker实战-如何去访问Docker仓库?

导语   仓库在之前的分享中我们介绍过,它主要的作用就是用来存放镜像文件,又可以分为是公共的仓库和私有仓库。有点类似于Maven的中央仓库和公司内部私服。 下面我们就来介绍一下在Docker中如何去访问各种仓库。 Docker Hub 公共镜像仓库 Docker Hub 是Docker官方提供的最…

基于JAVA SpringBoot和HTML校园二手商城系统设计

随着网络技术的飞跃&#xff0c;人类的社会生活和现代信息技术呈现出不断融合的趋势&#xff0c;生活中的日常账单支付、网上购物、网上学习和娱乐等。二手交易平台应运而生&#xff0c;其主要目的是充分交换人们闲置的产品。你可以在交易平台上发布二手商品&#xff0c;然后有…

promise中then和catch同时调用

promise同时执行then和catch 之前一直对promise中的then函数和catch有误区&#xff0c;以为resolve就直接走then&#xff0c;reject走catch&#xff0c;但在最近项目中遇到了then和catch同时触发。 下面我们来看一组例子 let count 0const func async () > {countComput…

CAD中快速加载卫星影像的免费插件

在对GIS矢量地图数据进行处理的工作中&#xff0c;我们经常会将卫星影像插入到CAD中作为底图&#xff0c;从而便于与矢量地图数据进行叠加对比&#xff0c;但怎样才能将带坐标的卫星影像快速插入到CAD中呢&#xff1f; CAD中卫星影像与矢量数据叠加 这里分享一个可以在CAD中加…

jacoco多版本报告合并

jacoco提供了一个merge命令可以给我方便的合并代码无变更时的报告&#xff0c;但是一旦代码发生变化&#xff0c;则无法通过jacoco进行直接合并&#xff0c;原因在《jacoco的多次代码提交merge分析》中已经说明&#xff0c;那么针对一次功能测试&#xff0c;势必会进行多轮&…

【C语言进阶(1)】数据存储

文章目录 Ⅰ 数据类型介绍⒈类型的基本分类 Ⅱ 整形在内存中的存储⒈原码、反码、补码⒉大小端介绍及判断大小端 Ⅲ 浮点型在内存中的存储⒈浮点数在内存中的存储规则⒉IEEE 754 对 M 和 E 的存取规定⒊解释前面的题目 Ⅰ 数据类型介绍 基本内置类型 类型类型名称char字符数据…

玄子Share - Mybatis 项目模板使用指南

玄子Share - Mybatis 项目模板使用指南 项目结构图 mybatis-config.xml 配置模板设置 参数 <?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "https://mybatis.…

pycharm运行pytest无法实时输出信息

需要去掉控制台输出。根据查询相关信息显示pycharm运行pytest无法实时输出信息&#xff0c;需要去掉pycharm里面的运行模式&#xff0c;点击减号&#xff0c;再点击加号&#xff0c;添加python执行文件即可实时输出信息。 问题描述&#xff1a; 使用pycharm运行代码时&#x…

24考研数据结构-树与森林

目录 5.4树、森林5.4.1树的存储结构1. 双亲表示法(顺序存储)&#xff1a;2. 孩子表示法(顺序链式)3. 孩子兄弟表示法&#xff08;链式&#xff09; 5.4.2树、森林与二叉树的转换5.4.3树、森林的遍历1. 树的遍历先根遍历后根遍历层序遍历&#xff08;队列实现&#xff09; 2. 森…

LeetCode-26-删除有序数组中的重复项

一&#xff1a;题目描述&#xff1a; 给你一个 升序排列 的数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff0c;返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。 考虑 nums 的唯…

AI相机“妙鸭相机”原理分析和手动实现方案

妙鸭相机 一个通过上传大约20张照片&#xff0c;生成专属自拍。在2023年7月末爆火&#xff0c;根据36Kr报道&#xff0c;妙鸭相机系阿里系产品&#xff0c;挂靠在阿里大文娱体系下&#xff0c;并非独立公司。 使用方法是上传20张自拍照片&#xff0c;之后可以选择模板生成自己…

神码ai火车头标题伪原创【php源码】

这篇文章主要介绍了如何把python 代码打包成可执行软件&#xff0c;具有一定借鉴价值&#xff0c;需要的朋友可以参考下。希望大家阅读完这篇文章后大有收获&#xff0c;下面让小编带着大家一起了解一下。 火车头采集ai伪原创插件截图&#xff1a; Python 程序封装-打包成exe程…

以指标驱动,保险、零售、制造企业开启精益敏捷运营的新范式

近日&#xff0c;以“释放数智生产力”为主题的 Kyligence 用户大会在上海前滩香格里拉大酒店成功举行。大会包含上午的主论坛和下午的 4 场平行论坛&#xff0c;并举办了闭门会议、Open Day 等活动。来自金融、零售、制造、医药等行业的客户及合作伙伴带来了超过 23 场主题演讲…