当前位置: 首页 > article >正文

cpp实战项目—string类的模拟实现

cpp—string类的模拟实现

  • string类的模拟实现
    • string.h
    • test.cpp

string类的模拟实现

相信大家看完我的这篇有关string使用的博客(C++中的string类使用,看我这一篇就够了!)之后对于string类的基本使用有了一定的了解,
因此这篇我们来看看string类底层是如何实现的!
在这之前我们需要了解的基本知识有
C++快速入门,看我这一篇就够了!
cpp – 构造函数与析构函数
cpp–拷贝构造函数详解
cpp–赋值运算符重载,浅显易懂!
cpp–初始化列表,超详细,一看就会!
cpp–内存管理(new/delete的用法),超详细讲解,一看就会!
C++中的string类使用,看我这一篇就够了!

string.h

#pragma once
#include <assert.h>

namespace s
{
	class string
	{
	public:
		typedef char* iterator;
		typedef const char* const_iterator;
		iterator begin()
		{
			return _str;
		}
		iterator end()
		{
			int length = _size;
			return _str + length;
		}
		const iterator begin() const
		{
			return _str;
		}

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

		string(const char* str = "")
			:_size(strlen(str))
			,_capacity(_size)
		{
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}
		//string(const string& s)//深拷贝构造函数
		//{
		//	_str = new char[s._capacity + 1];
		//	strcpy(_str, s._str);
		//	_size = s._size;
		//	_capacity = s._capacity;

		//}

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

		}
		//深拷贝构造函数的现代写法
		string(const string& s)
			:_str(nullptr)
			, _size(0)
			, _capacity(0)
		{
			string tmp(s._str);

			swap(tmp);
		}

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

		string& operator=(string tmp)
		{
			swap(tmp);

			return *this;
		}
		char* c_str()
		{
			return _str;
		}

		size_t capacity()
		{
			return _capacity;
		}

		size_t size()
		{
			return _size;
		}

		//bool operator<(const string& str) const
		//{
		//	size_t i = 0;
		//	//逐个字符比较,直到其中一个字符串结束
		//	while (i < _size && str._str[i] != '\0')
		//	{
		//		if (_str[i] > str._str[i])
		//		{
		//			return false;
		//		}
		//		else if (_str[i] < str._str[i])
		//		{
		//			return true;
		//		}
		//		i++;
		//	}
		//	if (i == _size && str._str[i] != '\0')
		//	{
		//		return true;
		//	}
		//	return false;
		//}


		bool operator<(const string& str) const
		{
			//size_t i = 0;
			 逐个字符比较,直到其中一个字符串结束
			//while (i < _size && i < str._size)
			//{
			//	if (_str[i] < str._str[i])
			//	{
			//		return true;
			//	}
			//	else if (_str[i] > str._str[i])
			//	{
			//		return false;
			//	}
			//	i++;
			//}
			 如果前面字符都相等,比较字符串长度
			//return _size < str._size;

			//使用库函数
			return strcmp(_str, str._str) < 0;
		}
		bool operator==(const string& s)
		{
			return strcmp(_str, s._str) == 0;
		}
		bool operator<=(const string& s)
		{
			return (*this < s) || (*this == s);
		}
		bool operator>(const string& s)
		{
			return !(*this <= s);
		}
		bool operator>=(const string& s)
		{
			return (*this == s) || (*this > s);
		}
		char& operator[](size_t pos)
		{
			assert(pos < _size);
			return _str[pos];
		}

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

		string& operator+=(const char* str)
		{
			append(str);
			return *this;
		}
		void clear()
		{
			_str[0] = '\0';
			_size = 0;
		}
		void reserve(size_t n)
		{
			if (n > _capacity)
			{
				char* tmp = new char[n + 1];
				strcpy(tmp,_str);
				delete[] _str;
				_str = tmp;
				_capacity = n;

			}
		}
		void push_back(char ch)
		{
			if (_size == _capacity)
			{
				reserve(_capacity == 0 ? 4 : _capacity * 2);
			}
			_str[_size] = ch;
			_size += 1;
			_str[_size] = '/0';
		}

		void append(const char* str)
		{
			int length = strlen(str)+_size;
			if(_capacity<length)
				reserve(length);
			strcpy(_str + _size, str);
			_size += strlen(str);
		}

		/*void insert(size_t pos, char ch) //方法一
		{
			assert(pos <= _size);
			if (_capacity == _size)
			{
				reserve(_capacity == 0 ? 4 : 2 * _capacity);
			}
			size_t end = _size+1;
			for (size_t i = end;i > pos;i--)
			{
				_str[i] = _str[i-1];

			}
			_str[pos] = ch;
			_size++;
			_str[_size] = '\0';
		}*/


		void insert(size_t pos, char ch) //方法二
		{
			assert(pos <= _size);
			if (_capacity == _size)
			{
				reserve(_capacity == 0 ? 4 : 2 * _capacity);
			}
			size_t end = _size;
			for (int i = (int)end;i >= (int)pos;i--)
			{
				_str[i+1] = _str[i];

			}
			_str[pos] = ch;
			_size++;
			_str[_size] = '\0';
		}

		void insert(size_t pos, const char* str)
		{
			int length = strlen(str);
			if (_size + length > _capacity)
			{
				reserve(_size+length);
			}
			for (int i = (int)_size; i >= (int)pos; i--)
			{
				_str[i + length] = _str[i];
			}
			strncpy(_str+pos, str, length);
			_size += length;
		}
		//strcpy:会复制整个源字符串,直到遇到字符串结束符 '\0',
		// 它不会对复制的字符数量进行额外的限制。
		// 如果目标字符串的空间不足以容纳源字符串,会导致缓冲区溢出,
		// 这是一种非常危险的情况,可能会引发程序崩溃或安全漏洞

		//strncpy:可以指定最多复制的字符数量 n。
		// 如果源字符串的长度小于 n,则会将源字符串全部复制到目标字符串,
		// 并且在目标字符串后面填充 '\0' 直到复制的字符总数达到 n;
		// 如果源字符串的长度大于等于 n,则只会复制 n 个字符,
		// 不会自动添加字符串结束符 '\0',
		// 这可能导致目标字符串不是以 '\0' 结尾的有效字符串
		string substr(size_t pos, size_t len = npos)
		{
			string s;
			size_t end = pos + len;

			if (pos + len >= _size || len == npos)
			{
				len = _size - pos;
				end = _size;

			}
			s.reserve(len);
			for (size_t i = pos;i < pos + len;i++)
			{
				s += _str[i];
			}

			return s;
		}

		void erase(size_t pos, size_t len = npos)
		{
			assert(pos < _size);
			if (pos + len >= _size || len == npos)
			{
				_str[pos] = '\0';
				_size = pos;
			}
			else
			{
				int end = pos + len;
				for (int i = pos+len; i <= _size; i++)
				{
					_str[i-len] = _str[i];
				}
				_size -= len;
				_str[_size] = '\0';
			}
		}

		void resize(int n, char ch = '\0')
		{
			if (n > _size)
			{
				reserve(n);
				while (_size < n)
				{
					_str[_size] = ch;
					++_size;
				}
				_str[_size] = '\0';
			}
			else if (n <= _size)
			{
				_str[n] = '\0';
				_size = n;
			}
		}

		size_t find(char ch, int pos = 0)
		{
			while (pos < _size)
			{
				if (ch == _str[pos])
				{
					return pos;
				}
				++pos;
			}
			return npos;
		}

		size_t find(const char* sub, int pos = 0)
		{
			const char* p = strstr(_str + pos, sub);//返回sub在字符串中第一次出现的位置
			if (p)
			{
				return p - _str;
			}
			else
			{
				return npos;
			}
		}
		const static size_t npos;

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

	};
	const  size_t string::npos = -1;


	istream& operator>>(istream& in, string& s)
	{
		s.clear();

		char buff[129];
		size_t i = 0;

		char ch;
		ch = in.get();
		while (ch != ' ' && ch != '\n')
		{
			buff[i++] = ch;
			if (i == 128)
			{
				buff[i] = '\0';
				s += buff;
				i = 0;
			}
			ch = in.get();
		}
		if (i != 0)
		{
			buff[i] = '\0';
			s += buff;
		}

		return in;
	}
	ostream& operator<<(ostream& out, const string& s)
	{
		for (auto ch : s)
		{
			out << ch;
		}
		return out;
	}
	void test_string1()
	{
		string s1("hello world");
		cout << s1.c_str() << endl;

		string s2;
		cout << s2.c_str() << endl;

		cout << s1.size() << endl;
		cout << s2.size() << endl;

		cout << s1.capacity() << endl;
		cout << s2.capacity() << endl;

		for (size_t i = 0; i < s1.size();i++)
		{
			cout << s1[i] ;
		}
		cout << endl;
		string::iterator it = s1.begin();
		while (it != s1.end())
		{
			cout << *it << " ";
			++it;
		}
		cout << endl;
		for (auto& ch : s1)
		{
			cout << ch << " ";
		}

	}

	void test_string2()
	{
		string s1("hello world");
		cout << s1.c_str() << endl;
		s1.push_back(' ');
		s1.append("hello boy");

		cout << s1.c_str() << endl;

	}

	void test_string3()
	{
		string s1("hello world");
		cout << s1.c_str() << endl;
		s1.insert(0, '%');
		//在头插时可能出现的问题
		//在将元素后移的 for 循环中,for (size_t i = end; i >= pos; i--) 
		// 会导致无限循环。因为 size_t 是无符号整数类型,
		// 当 i 减到 0 后再减 1 会变成一个很大的正数(发生下溢),
		// 而不是负数,所以循环条件 i >= pos 始终为真。
		// 可以将循环变量改为有符号整数类型,或者从后往前移动元素
		cout << s1.c_str() << endl;

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

	}

	void test_string4()
	{
		string s1("hello worad");
		string s2("hello worsld");
		cout << (s1 < s2) << endl;

		s1[0] = 'z';
		cout << (s1 >= s2) << endl;

		cin >> s1>>s2;
		cout << s1 <<s2<< endl;

		
	}

	void test_string5()
	{
		string s1("hello world");
		s1.insert(5, "abc");
		s1.insert(0, "xxx");
		cout << s1 << endl;
		s1.erase(0, 3);
		cout << s1 << endl;
		s1.erase(5, 100);
		cout << s1 << endl;
	}

	void test_string6()
	{
		string s1("hello world");
		cout << s1 << endl;

		s1.resize(5);
		cout << s1 << endl;

		s1.resize(25, 'x');
		cout << s1 << endl;
	}
	void test_string7()
	{
		string s1("test.cpp.tar.zip");
		//size_t i = s1.find('.');
		//size_t i = s1.rfind('.');

		//string s2 = s1.substr(i);
		//cout << s2 << endl;

		string s3("https://legacy.cplusplus.com/reference/string/string/rfind/");
		//string s3("ftp://www.baidu.com/?tn=65081411_1_oem_dg");
		// 协议
		// 域名
		// 资源名

		string sub1, sub2, sub3;
		size_t i1 = s3.find(':');
		if (i1 != string::npos)
			sub1 = s3.substr(0, i1);
		else
			cout << "没有找到i1" << endl;

		size_t i2 = s3.find('/', i1 + 3);
		if (i2 != string::npos)
			sub2 = s3.substr(i1 + 3, i2 - (i1 + 3));
		else
			cout << "没有找到i2" << endl;

		sub3 = s3.substr(i2 + 1);

		cout << sub1 << endl;
		cout << sub2 << endl;
		cout << sub3 << endl;
	}

	void test_string8()
	{
		string s1("hello world");
		string s2 = s1;
		cout << s1 << endl;
		cout << s2 << endl;


		string s3("xxxxxxxxxxxxxxx");
		s1 = s3;
		cout << s3 << endl;
	}

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

test.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string>
using namespace std;
#include "string.h"
int main()
{
	s::test_string9();
	return 0;
}

http://www.kler.cn/a/528421.html

相关文章:

  • 【深度分析】微软全球裁员计划不影响印度地区,将继续增加当地就业机会
  • Java小白入门教程:三种注释+快捷方式
  • Golang :用Redis构建高效灵活的应用程序
  • DBeaver连接MySQL提示Access denied for user ‘‘@‘ip‘ (using password: YES)的解决方法
  • 使用 Docker + Nginx + Certbot 实现自动化管理 SSL 证书
  • java求职学习day23
  • 微机原理与接口技术期末大作业——4位抢答器仿真
  • 神经网络的数据流动过程(张量的转换和输出)
  • 小程序设计和开发:什么是竞品分析,如何进行竞品分析
  • 代码随想录刷题day22|(字符串篇)344.反转字符串、541.反转字符串 II
  • 【数据结构】_复杂度
  • JavaScript前后端交互-AJAX/fetch
  • 记4(可训练对象+自动求导机制+波士顿房价回归预测
  • Docker 部署 GLPI(IT 资产管理软件系统)
  • LabVIEW无人机航线控制系统
  • 8 比例缩放(scale.rs)
  • 我用Ai学Android Jetpack Compose之Row
  • .Net Web API 访问权限限定
  • JavaFX - 3D 形状
  • 如何使用 ChatBox AI 简化本地模型对话操作
  • ROS-激光雷达模块学习[粗]
  • 算法随笔_35: 每日温度
  • kamailio-ACC_JSON模块详解【后端语言go】
  • 数据结构(1)——算法时间复杂度与空间复杂度
  • 4. 劲舞团python解法——2024年省赛蓝桥杯真题
  • Kafka分区策略实现