模拟实现string

模拟实现string只是仿造库里的功能模拟实现,并不和库中代码一样。需要知道的是,string在不同的编译器下,string的实现也是有差异的。

#pragma once
#include <assert.h>
namespace QiBL
{
	class string
	{
	public:
		typedef char* iterator;//将iterator写在类里面,这样每一个类都有自己的iterator,所以使用的时候要指定是哪个类的迭代器,迭代器像指针但是可能不是指针
		typedef const char* const_iterator;
		iterator begin()//begin指向头
		{
			return _str;
		}
		iterator end()//end指向尾的下一个,即"\0"
		{
			return _str + _size;
		}
		const_iterator begin() const//begin指向头
		{
			return _str;
		}
		const_iterator end() const//end指向尾的下一个,即"\0"
		{
			return _str + _size;
		}
	public:
		string(const char* str = "")//空串自动保留一个"\0",不能使用nullptr,不然在c_str函数返回会报错
			//:_str(new char[1])//开一个空间存"\0"标识符
			//, _size(0)//_size表示存了多少数据 不算"\0"
			//, _capacity(0)//_capacity表示能存多少数据 不算"\0"
			: _size(strlen(str))
		{
			_capacity = _size;//最开始_capacity与_size大小相同,都是初始化的大小,不包含"\0"
			_str = new char[_capacity + 1];//strlen计算字符串大小的时候不算"\0",所以开空间的时候多加了1
			strcpy(_str, str);
		}

		/*string(const string& s)
		{
			_str = new char[s._capacity + 1];
			_size = s._size;
			_capacity = s._capacity;
			strcpy(_str, s._str);
		}*/
		string(const string& s)
		{
			string tmp(s._str);
			swap(tmp);
		}

		char* c_str() const
		{
			return _str;
		}

		size_t size() const//加const,保证const对象也能调用
		{
			return _size;
		}
		size_t capacity() const//加const,保证const对象也能调用
		{
			return _capacity;
		}

		char& operator[](size_t i)//为了可读可写,所以使用引用返回,因为在堆上,所以函数结束数据还在
		{
			assert(i < _size);
			return _str[i];
		}

		const char& operator[](size_t i) const//只读,加const,保证const对象也能调用
		{//前面加const是为了返回值是引用,会被其他引用改变返回位置的值
			assert(i < _size);
			return _str[i];
		}
		void reserve(size_t n)//扩容	
		{
			if (n > _capacity)//n比_capacity大才扩容,否则不变,不能缩容
			{
				char* tmp = new char[n + 1];
				strcpy(tmp, _str);
				delete[] _str;
				_str = tmp;
				_capacity = n;
			}
		}

		void push_back(char c)//尾插一个字符
		{
			if (_size == _capacity)
				reserve(_capacity == 0 ? 4 : _capacity * 2);
			_str[_size] = c;
			++_size;
			_str[_size] = '\0';
		}

		void append(const char* str)//尾插一个字符串
		{
			size_t len = strlen(str);
			if ((_size + len) > _capacity)
			{
				reserve(_size + len);
			}
			strcpy(_str + _size, str);//strcpy会将'\0',也拷贝过来
			_size += len;
		}

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

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

		/*string& operator=(const string& 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& operator=(string s)
		{
			swap(s);
			return *this;
		}

		void insert(size_t pos, char c)//在pos前插入字符c,下表从0开始,0是头插,等于_size就是尾插
		{
			assert(pos <= _size);
			if (_size == _capacity)
				reserve(_capacity == 0 ? 4 : _capacity * 2);
			size_t end = _size + 1;//end指向'\0'的下一个
			while (pos < end)
			{
				_str[end] = _str[end - 1];
				--end;
			}
			_str[pos] = c;
			++_size;
		}

		void insert(size_t pos, const char* str)
		{
			assert(pos <= _size);
			size_t len = strlen(str);
			if ((_size + len) > _capacity)
				reserve(_size + len);
			size_t end = _size + len;
			//while (end - len > pos - 1)//pos可能是0,所以要写为加
			while (end > pos + len - 1)
			{
				_str[end] = _str[end - len];
				--end;
			}
			strncpy(_str + pos, str, len);
			_size = _size + len;
		}

		void erase(size_t pos = 0, size_t len = npos)//从pos位置删除len个
		{
			assert(pos < _size);//位置是 0 - size - 1
			//if (len == npos || pos + len >= _size)//这样写有BUG,有溢出的风险,假设len = nops - 1
			if (len == npos || len >= _size - pos)//这种写法可以规避掉风险
			{
				_str[pos] = '\0';
				_size = pos;
			}
			else
			{
				strcpy(_str + pos, _str + pos + len);
				_size = _size - len;
			}
		}

		void resize(size_t n, char c = '\0')//改变有效数据的大小,但是不缩容
		{
			if (n <= _size)
			{
				_str[n] = '\0';
				_size = n;
			}
			else
			{
				reserve(n);
				for (size_t i = _size; i < n; i++)
				{
					_str[i] = c;
				} 
				_size = n;
				_str[_size] = '\0';
			}
		}

		void swap(string& s)
		{
			std::swap(_str, s._str);
			std::swap(_size, s._size);
			std::swap(_capacity, s._capacity);
		}
			
		size_t find(char ch, size_t pos = 0)//指定位置开始,找字符返回下标,找不到就返回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* sub, size_t pos = 0)//指定位置开始,找字符串返回下标,找不到就返回npos
		{
			assert(pos < _size);
			char* p = strstr(_str + pos, sub);//strstr是C语言库中匹配字符串的库函数
			if (p)
			{
				return p - _str;
			}
			return npos;
		}

		string substr(size_t pos = 0, size_t n = npos)//指定位置取长度为n的字符串
		{
			assert(pos < _size);
			string s;
			if (n >= _size - pos)//从下标0开始
			{
				for (size_t i = pos; i < _size; i++)
				{
					s += _str[i];
				}
			}
			else
			{
				for (size_t i = pos; i < pos + n; i++)
				{
					s += _str[i];
				}
			}
			return s;
		}

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

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

	private:
		char* _str = nullptr;
		size_t _size = 0;
		size_t _capacity = 0;
	public:
		static const int npos;
	};
	bool operator==(const string& s1, const string& s2)
	{
		int ret = strcmp(s1.c_str(), s2.c_str());
		return ret == 0;
	}

	bool operator<(const string& s1, const string& s2)
	{
		int ret = strcmp(s1.c_str(), s2.c_str());//s1小于s2返回-1
		return ret < 0;
	}

	bool operator<=(const string& s1, const string& s2)
	{
		if (s1 < s2 || s1 == s2)
			return true;
		else
			return false;
	}
	bool operator>(const string& s1, const string& s2)
	{
		if (s1 <= s2)
			return false;
		else
			return true;
	}
	bool operator>=(const string& s1, const string& s2)
	{
		if (s1 < s2)
			return false;
		else
			return true;
	}

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

	istream& operator>>(istream& in, string& s)
	{
		s.clear();
		char ch;
		//in >> ch;//C++的cin和C语言的scanf不支持提取空格和换行
		ch = in.get();//推荐使用istream类的get(),类似get char(),但是更好
		while (ch != ' ' && ch != '\n')
		{
			s += ch;
			ch = in.get();
		}
		return in;
	}

	istream& getline(istream& in, string& s)//一次输入一行内容
	{
		s.clear();
		char ch;
		//in >> ch;//C++的cin和C语言的scanf不支持提取空格和换行
		ch = in.get();//推荐使用istream类的get(),类似get char(),但是更好
		while (ch != '\n')
		{
			s += ch;
			ch = in.get();
		}
		return in;
	}

	const int string::npos = -1;
	void Stringtest1()
	{
		string s1 = "Hello World";
		for (int i = 0; i < s1.size(); i++)
		{
			cout << s1[i] << " ";
		}
		cout << endl;
		s1[1] = 'W';
		for (int i = 0; i < s1.size(); i++)
		{
			cout << s1[i] << " ";
		}
		cout << endl;
		string s2 = "Wello World";
		for (int i = 0; i < s2.size(); i++)
		{
			cout << s2[i] << " ";
		}
		cout << endl;
		cout << "Stringtest1()" << endl;
	}
	void Stringtest2()
	{
		string s3 = "Hello World";
		string::iterator i3 = s3.begin();
		while (i3 != s3.end())
		{
			(*i3)++;
			cout << *i3 << " ";
			
			i3++;
		}
		cout << endl;

		for (auto i : s3)//经尝试,范围for只识别begin和end,当iterator换成其他宏,只要begin和end在就能使用,且begin和end的大小写不能换
		{//范围for底层是一个死板的替换,并不神秘
			i--;
			cout << i << " ";
		}
		cout << endl;

		cout << "Stringtest2()" << endl;
	}
	void Stringtest3()
	{
		const string s4 = "Hello World";
		string::const_iterator i4 = s4.begin();
		while (i4 != s4.end())
		{
			//(*i4)++;
			cout << *i4 << " ";
			i4++;
		}
		cout << endl;

		//虽然s4被const修饰,但是范围for得到的是s4的拷贝,所以修改的也是临时变量的值,所以不会报错
		/*for (auto& i : s4)
		{
			i--;
			cout << i << " ";
		}
		cout << endl;*/
		//
		for (auto& i : s4)//范围for使用引用就不是拷贝了
		{//综上可以看出,范围for是相当于函数传参一般
			//i--;
			cout << i << " ";
		}
		cout << endl;
		cout << "Stringtest3()" << endl;
	}
	void Stringtest4()
	{
		string s4 = "Hello World";
		s4.push_back('H');
		cout << s4.c_str();
		cout << endl;
		cout << "Stringtest4()" << endl;
	}
	void Stringtest5()
	{
		string s4 = "Hello World";
		s4 += "XYZ";
		s4 += "QBL";
		s4 += "Q";
		cout << s4.c_str()<< endl;
		cout << "Stringtest5()" << endl;
	}
	void Stringtest6()
	{
		string s4 = "Hello World";
		s4.insert(11, 'Q');
		cout << s4.c_str() << endl;
		cout << "Stringtest6()" << endl;
	}
	void Stringtest7()
	{
		string s4 = "Hello World";
		s4.insert(0, "QQQ");
		cout << s4.c_str() << endl;
		cout << "Stringtest7()" << endl;
	}
	void Stringtest8()
	{
		string s4 = "Hello World";
		s4.erase(10);
		cout << s4.c_str() << endl;
		cout << "Stringtest8()" << endl;
	}
	void Stringtest9()
	{
		string s4 = "Hello World";
		s4.resize(5);
		cout << s4.c_str() << endl;
		s4.resize(10, 'x');
		cout << s4.c_str() << endl;
		cout << "Stringtest9()" << endl;
	}
	void Stringtest10()
	{
		string s4 = "Hello World";
		string s5 = s4;
		cout << s4.c_str() << endl;
		s5.erase(5, 3);
		cout << s5.c_str() << endl;
		cout << "Stringtest10()" << endl;
	}
	void Stringtest11()
	{
		string s4 = "Hello World";
		string s5 = s4.substr(10);
		cout << s5.c_str() << endl;
		cout << "Stringtest11()" << endl;
	}
	void Stringtest12()
	{
		string s4 = "Hello World";
		string s5 = "Hello World";
		cout << (s5 == s4) << endl;
		cout << "Stringtest12()" << endl;
	}
	void Stringtest13()
	{
		string s4 = "Hello World";
		string s5 = "Hello World1";
		cout << (s5 == s4) << endl;
		cout << (s5 > s4) << endl;
		cout << (s5 < s4) << endl;
		cout << (s5 >= s4) << endl;
		cout << (s5 <= s4) << endl;
		cout << "Stringtest13()" << endl;
	}
	void Stringtest14()
	{
		string s4 = "Hello World";
		cout << s4 << endl;
		cout << "Stringtest14()" << endl;
	}
	void Stringtest15()
	{
		string s4 = "Hello World";
		cout << s4 << endl;
		string s5 = "Hello World";
		cout << s4 << endl;
		cin >> s4 >> s5;
		cout << s4 << endl;
		cout << s5 << endl;
		cout << "Stringtest15()" << endl;
	}
	void Stringtest16()
	{
		string s4 = "Hello World";
		cout << s4 << endl;
		getline(cin, s4);
		cout << s4 << endl;
		cout << "Stringtest16()" << endl;
	}
}

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值