栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

【C++】-- String模拟实现

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【C++】-- String模拟实现

string的模拟实现,模拟实现包括string类的构造、拷贝构造、赋值运算符重载、析构、迭代器、swap、operator[ ]、size()、c_str()、reserve() 、resize()、push_back()、append()、operator+=()、insert()、erase()、find()、operator>、operator==、operator>=、operator<、operator<=、operator!=、clear()、operator<<、operator>>函数 

#pragma  once  
#define  _CRT_SECURE_NO_WARNINGS
#include
#include
#include

using namespace std;
//定义一个新的命名空间,和全局命名空间隔离开
namespace delia
{
	class string
	{
	public:

		typedef char* iterator;

		//迭代器
		iterator begin()
		{
			return _str;
		}

		//迭代器
		iterator end()
		{
			return _str + _size;
		}

		//const迭代器
		iterator begin() const 
		{
			return _str;
		}

		//const迭代器
		iterator end() const
		{
			return _str + _size;
		}

		//构造函数
		string(const char* str = "")
		{
			_str = new char[strlen(str) + 1];//1是留给'/0'的,_size最大为申请字节数-1,_capacity也为申请字节数-1
			strcpy(_str, str);

			_size = strlen(str);
			_capacity = _size;
		}

		//现代拷贝构造
		string(const string& s)
			:_str(nullptr)
			, _size(0)
			, _capacity(0)
		{
			string tmp(s._str);
			swap(tmp);
		}

		//赋值运算符重载
		string& operator=(string s)
		{
			swap(s);
			return *this;
		}

		//析构函数
		~string()
		{
			delete[] _str;
			_str = nullptr;
			_size = 0;
			_capacity = 0;
		}

		//实现交换函数
		void swap(string& s)
		{
			::swap(_str, s._str);//用::指定调用全局的swap函数即库里的swap函数
			::swap(_size, s._size);
			::swap(_capacity, s._capacity);
		}

		//const string对象遍历,只读
		char& operator[](size_t i)  const//char要加&,如果不加,那么return就是传值返回,返回的是_str[i]的拷贝,临时对象,而临时对象具有常性,不能被修改,只能读
										 //如果要对_str进行修改的话,char要加&,用传引用返回
		{
			assert(i < _size);
			return _str[i];
		}

		//非const string对象遍历,可读可写
		char& operator[](size_t i)
		{
			assert(i < _size);
			return _str[i];
		}

		//求string对象大小
		size_t size() const
		{
			return strlen(_str);
		}

		//获取c形式字符串,将 const string* 类型 转化为 const char* 类型
		const char* c_str()
		{
			return _str;
		}

		//开空间,扩展_capacity,_size不变
		void reserve(size_t n)
		{
			//1.申请新空间
			//2.拷贝字符串
			//3.释放旧空间
			//4.指向新空间
			//5.更新容量
			if (n > _capacity)
			{
				char* tmp = new char[n + 1];//1.申请新空间,多开的那一个空间,存放
				strncpy(tmp, _str, _size + 1);//2.将字符串包含在内都拷贝到新空间
				delete[] _str;//3.释放旧空间

				_str = tmp;//4.指向新空间
				_capacity = n;//5.更新容量
			}
		}

		//开空间+初始化,扩展_capacity,_size也要修改
		void resize(size_t n, char val = '')//如果没有显式给出val,val为
		{
			//1.当n<_size,无需增容
			if (n < _size)
			{
				_size = n;//直接更新_size
				_str[_size] = '';//将_size位置置为
			}
			//2.当n>_size,分两种情况
			//(1)_size < n <_capacity,无需增容,直接将_size到n位置置为val
			//(2)n >_capacity,需增容,并将_size到n位置置为val
			//这两种情况只有是否增容的区别,其他没有区别
			else
			{
				if (n > _capacity)
				{
					reserve(n);
				}

				for (size_t i = _size; i < n; i++)
				{
					_str[i] = val;
				}

				_str[n] = '';//将n的位置置
				_size = n;//更新_size
			}
		}

		//尾插一个字符
		void push_back(char ch)
		{
			//字符个数已经达到容量时,重新开空间
			if (_size == _capacity)
			{
				reserve(_capacity == 0 ? 4 : _capacity * 2);//如果是第一次开空间,就开4个字节,如果不是第一次开空间,就开成原来的2倍容量
			}

			_str[_size] = ch;//将字符ch缀到字符串末尾
			_str[_size + 1] = '';//字符ch后面加,表明字符串结束
			_size++;//字符串大小+1
		}

		//追加字符串
		void append(const char* str)
		{
			size_t len = _size + strlen(str);//函数执行完毕后字符串的大小

			if (len > _capacity)
			{
				reserve(len);//空间不够,增容
			}

			strcpy(_str + _size, str);//将str内容拷贝至_str末尾
			_size = len;//更新_size
		}

		//+= 1个字符
		string& operator+= (char c)
		{
			push_back(c);//尾插字符
			return *this;
		}

		//+= 字符串
		string& operator+= (const char* str)
		{
			append(str);//拼接字符串
			return *this;
		}

		//insert插入一个字符
		string& insert(size_t pos, const char ch)
		{
			assert(pos <= _size);//pos必须小于等于字符串长度

			if (_size == _capacity)
			{
				reserve(2 * _capacity);//如果满了就增容
			}

			size_t end = _size + 1;
			while (end > pos)//将pos至_size之间的字符依次向后挪动一个位置,来腾出pos位置
			{
				_str[end] = _str[end - 1];
				end--;//end为0时,因此end类型应为int,那么end--就为-1,pos为无符号数,不满足循环条件,退出循环
					  //但如果end类型为size_t,那么end为0时,end--就为-1,在内存中存储为无符号数(-1补码全1),满足循环条件,永远无法退出循环
			}

			_str[pos] = ch;//pos位置插入ch
			_size++;//更新_size

			return *this;
		}

		//erase 删除字符
		string& erase(size_t pos, size_t len = npos)
		{
			assert(pos < _size);

			size_t leftLen = _size - pos;//从pos位置到字符串结束的字符长度
			if (leftLen < len)//1.pos之后的字符全部删掉
			{
				_str[pos] = '';
				_size = pos;
			}
			else//2.pos之后的字符删掉一部分,没删完的部分要挪到pos位置
			{
				strcpy(_str + pos, _str + pos + len);
				_size -= len;
			}
			return *this;
		}

		//查找字符
		size_t find(char ch, size_t pos = 0)
		{
			assert(pos < _size);
			for (size_t i = 0; i < _size; i++)
			{
				if (_str[i] == ch)
				{
					return i;//找到就返回字符所在位置
				}
			}
			return npos;//没找到就返回-1
		}

		//查找字符串(子串)
		size_t find(const char* str, size_t pos = 0)
		{
			assert(pos < _size);
			const char* ret  = strstr(_str + pos, str);

			if (ret)
			{
				return ret - _str;//计算str与_str的偏移量,即str在_str中的下标
			}
			else
			{
				return npos;//没找到就返回-1
			}
		}
		

		//字符串比较,只需要实现>和==
		bool operator>(const string& s)
		{
			return strcmp(_str, s._str) < 0;
		}

		bool operator==(const string& s)
		{
			return strcmp(_str, s._str) == 0;
		}

		// 其它4个运算符都可以对>和==这两个运算符进行重载
		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);
		}

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

		void clear()
		{
			_size = 0;
			_str[0] = '';
		}

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

		static const size_t npos;
	};

	const size_t string::npos = -1;//npos初始化

	//输出重载<<让string直接输出打印,像内置类型一样,用范围for就可以实现
	ostream& operator<<(ostream& out, const string& s)
	{
		for (auto ch: s)
		{
			out << s;
		}
		return out;
	}

	//输入重载>>让string直接输入,像内置类型一样;从标准输入流读取字符,遇到' '或''就停止
	istream& operator>>(istream& in, string& s)
	{
		s.clear();
		char ch;
		ch = in.get();
		while (ch != ' ' && ch != '')
		{
			s += ch;
			ch = in.get();
		}
		return in;
	}

	void f(const string& s)
	{
		for (size_t i = 0; i < s.size(); i++)
		{
			cout << s[i] << " ";
		}
		cout << endl;
	}

	void test_string1()
	{
		string s1("hello world");
		string s2(s1);

		string s3("cplusplus.com");
		std::swap(s1, s3);//调用库里的swap函数,3次深拷贝,再把原来的空间释放掉,再开一样大的空间,代价大
		s1.swap(s3);//调用delia::string类里面的成员函数swap,仅仅只是成员变量的交换,s3指向了s1的空间,s1指向了s3的空间

		string s4 = s1.c_str();
		s1[2] = 'w';
		f(s1);//h e w l o   w o r l d

		for (size_t i = 0; i < s1.size(); i++)
		{
			cout << s1[i] << " ";
		}
		cout << endl;//h e w l o   w o r l d
	}

	void test_string2()
	{
		string s1("hello world");

		//使用迭代器遍历
		string::iterator it = s1.begin();
		while (it != s1.end())
		{
			cout << *it << " ";
			it++;
		}
		cout << endl;//h e l l o   w o r l d

		//使用范围for遍历,范围for会被编译器替换成迭代器形式,如果把17-26行屏蔽,会发现编译不过
		for (auto ch : s1)
		{
			cout << *it << " ";
		}
		cout << endl;//h e l l o   w o r l d
	}

	void test_string3()
	{
		string s1("hello world");
		s1 += "abc";
		for (auto& ch : s1)
		{
			cout << ch << " ";
		}
		cout << endl;//h e l l o   w o r l d a b c

		s1 += "xyz";
		for (auto& ch : s1)
		{
			cout << ch << " ";
		}
		cout << endl;//h e l l o   w o r l d a b c x y z
	}

	void test_string4()
	{
		string s1("hello world");
		s1 += '#';
		for (auto ch : s1)
		{
			cout << ch << " ";
		}
		cout << endl;//hello world#

		s1 += "xyz";
		for (auto ch : s1)
		{
			cout << ch << " ";
		}
		cout << endl;//hello world#xyz

		s1 += "!!!!!!!!!!!!!!!!!!!!";
		for (auto ch : s1)
		{
			cout << ch << " ";
		}
		cout << endl;//hello world#xyz!!!!!!!!!!!!!!!!!!!!
	}

	void test_string5()
	{
		string s1("hello world");
		s1.resize(3);
		cout << s1.c_str() << endl;//hel
	}

	void test_string6()
	{
		string s1("hello");
		s1.resize(6, 'a');
		cout << s1.c_str() << endl;//helloa
	}

	void test_string7()
	{
		string s1("hello");
		s1.resize(9, 'o');
		cout << s1.c_str() << endl;//helloooo
	}

	void test_string8()
	{
		string s1("hello");
		s1.insert(0, 'u');
		cout << s1.c_str() << endl;//uhello
	}

	void test_string9()
	{
		string s1("hello");
		s1.erase(0, 2);
		cout << s1.c_str() << endl;//llo

		string s2("world");
		s2.erase(1);//如果不给len,那么npos=-1,无符号数为4294967295,删除从位置为1-4294967295的字符,把后面的字符全部删除了
		cout << s2.c_str() << endl;//w
	}


	void test_string10()
	{
		string s1("hello world");
		cout << s1.find("rl",6) << endl;//8,从s1中的第6个位置开始查找"rl"字符串
	}

	void test_string11()
	{
		std::string s("hello");
		cin >> s;
		cout << s << endl;
	}
}


int main()
{
	//delia::test_string1();
	//delia::test_string2();
	//delia::test_string3();
	//delia::test_string4();
	//delia::test_string5();
	//delia::test_string6();
	//delia::test_string7();
	//delia::test_string8();
	//delia::test_string9();
	//delia::test_string10();
	delia::test_string11();
	return 0;
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/920653.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号