前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[C++]string及其模拟实现

[C++]string及其模拟实现

作者头像
IT编程爱好者
发布2023-05-11 09:29:58
2510
发布2023-05-11 09:29:58
举报
文章被收录于专栏:C/C++爱好者

string及其模拟实现::

1.构造函数

代码语言:javascript
复制
//注意: '\0' "\0" ""的区别
string(const char* str = "")
{
	 //对空指针不能strlen
	 _size = strlen(str);
	 _capacity = _size;
	 _str = new char[_capacity + 1];
	 strcpy(_str, str);
}

2.拷贝构造函数

传统写法:

代码语言:javascript
复制
//拷贝构造传统写法
//s2(s1)
string(const string& s)
{
	_str = new char[s._capacity + 1];
	_capacity = s.capacity();
	_size = s._size;
	strcpy(_str, s._str);
}

现代写法:

代码语言:javascript
复制
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);//构造函数
		//交换s2和tmp
		//this->swap(tmp);
		swap(tmp);
}

3.赋值运算符重载

传统写法:

代码语言:javascript
复制
//赋值重载传统写法:
//s1=s3
string& operator=(const string& s)
{
		if (this != &s)
		{
			char* tmp = new char[s._capacity + 1];
			strcpy(tmp, s._str);
			//释放s1的旧空间
			delete[] _str;
			_str = tmp;
			_size = s._size;
			_capacity = s._capacity;
		}
		return *this;
}

现代写法:

代码语言:javascript
复制
//赋值重载现代写法:
//s1=s3
//string& operator=(const string& s)
//{
//	//string tmp(s._str);
//	string tmp(s);
//	swap(tmp);
//	return *this;
//}
//s1=s3
string& operator=(string s)
{
	//不用传引用传参 就用传值传参 s是s3的拷贝构造
	swap(s);
	return *this;
}

4.析构函数

代码语言:javascript
复制
~string()
{
	delete[] _str;
	_str = nullptr;
	_size = _capacity = 0;
}

5.string中的小接口

代码语言:javascript
复制
const char* c_str() const
{
	return _str;
}
size_t size() const
{
	return _size;
}
size_t capacity() const
{
	return _capacity;
}
void clear()
{
    _arr[0] = '\0';
    _size = 0;
}

6.operator[]的运算符重载

代码语言:javascript
复制
//普通对象可读可写
char& operator[](size_t pos)
{
	assert(pos < _size);
	return _str[pos];
}
//const对象:只读
const char& operator[](size_t pos) const
{
	assert(pos < _size);
	return _str[pos];
}

7.迭代器

代码语言:javascript
复制
typedef char* iterator;
iterator begin()
{
	return _str;
}
iterator end()
{
	return _str + _size;
}

8.reserve和resize

代码语言:javascript
复制
void reserve(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)
	{
		reserve(n);
		for (size_t i = _size; i < n; ++i)
		{
			_str[i] = ch;
		}
		_size = n;
		_str[_size] = '\0';
	}
	else
	{
		_str[n] = '\0';
		_size = n;
	}
}

9.push_back、append和+=的重载

代码语言:javascript
复制
void push_back(char ch)
{
	if (_size == _capacity)
	{
		size_t newCapacity = _capacity == 0 ? 4 : _capacity * 2;
		reserve(newCapacity);
	}
	_str[_size] = ch;
	++_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);
		_size += len;
	}
}
string& operator+=(char ch)
{
	push_back(ch);
	return *this;
}
string& operator+=(const char* str)
{
	append(str);
	return *this;
}

10.insert、erase和find

代码语言:javascript
复制
string& insert(size_t pos, char ch)
{
	assert(pos <= _size);
	if (_size == _capacity)
	{
		size_t newCapacity = _capacity == 0 ? 4 : _capacity * 2;
		reserve(newCapacity);
	}
	//挪动数据
	//int end = _size;
	//操作符两边的操作数类型不一样时会发生隐式类型的提升 解决办法1:将pos强转为int
	//注意: >= 一定要强转 如果想用无符号 判断部分就不能是>=
	/*while (end >= (int)pos)
	{
		_str[end + 1] = _str[end];
		--end;
	}*/
	//解决方法2:将_str[end-1]赋值给_str[end]
	size_t end = _size + 1;
	while (end > pos)
	{
		_str[end] = _str[end - 1];
		--end;
	}
	_str[pos] = ch;
	++_size;
	return *this;
}
string& insert(size_t pos, const char* str)
{
	size_t len = strlen(str);
	if (_size + len > _capacity)
	{
		reserve(_size + len);
	}
	/*int end = _size;
	while (end >= (int)pos)
	{
		_str[end + len] = _str[end];
		--end;
	}*/
	size_t end = _size + len;
	//问题:当end < len _str[end - len]存在越界 
	//while (end > pos)
	while (end >= pos + len)
	{
		_str[end] = _str[end - len];
		--end;
	}
	//使用strcpy(_str + pos,str)会拷贝\0使字符串提前结束
	strncpy(_str + pos, str, len);
	_size += len;
	return *this;
}
string& erase(size_t pos, size_t len = npos)
{
	assert(pos < _size);
	if (len == npos || pos + len >= _size)
	{
		_str[pos] = '\0';
		_size = pos;
	}
	else
	{
		strcpy(_str + pos, _str + pos + len);
		_size -= len;
	}
	return *this;
}
size_t find(char ch, size_t pos = 0) const
{
	assert(pos < _size);
	while (pos < _size)
	{
		if (_str[pos] == ch)
		{
			return pos;
		}
		++pos;
	}
	return npos;
}
size_t find(const char* str, size_t pos = 0) const
{
	assert(pos < _size);
	const char* ptr = strstr(_str + pos, str);
	if (ptr == nullptr)
	{
		return npos;
	}
	else
	{
		return ptr -> _str;
	}
}

11.<<和>>的运算符重载

代码语言:javascript
复制
ostream& operator<<(ostream& out, const string& s)
{
	for (size_t i = 0; i < s.size(); ++i)
	{
		out << s[i];
	}
	return out;
}
istream& operator>>(istream& in, const string& s)
{
	/*char ch;
	cin >> ch;
	while (ch != ' ' && ch != '\n')
	{
		s += ch;
		cin >> ch;
	}*/
	/*char ch = in.get();
	while (ch != ' ' && ch != '\n')
	{
		s += ch;
		ch = in.get();
	}*/
	//该写法不需要频繁扩容
	s.clear();
	char buff[128] = { '\0' };
	size_t i = 0;
	char ch = in.get();
	while (ch != ' ' && ch != '\n')
	{
		if (i == 127)
		{
			//满了
			s += buff;
			i = 0;
		}
		buff[i++] = ch;
		ch = in.get();
	}
	if (i >= 0)
	{
		buff[i] = '\0';
		s += buff;
	}
	return in;
}

12.模拟实现string的整体代码

代码语言:javascript
复制
#include<iostream>
#include<assert.h>
using namespace std;
namespace TXLF
{
	class string
	{
	public:
		typedef char* iterator;
		iterator begin()
		{
			return _str;
		}
		iterator end()
		{
			return _str + _size;
		}
		//注意: '\0' "\0" ""的区别
		string(const char* str = "")
		{
			//对空指针不能strlen
			_size = strlen(str);
			_capacity = _size;
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}
		void swap(string& s)
		{
			std::swap(_str, s._str);
			std::swap(_size, s._size);
			std::swap(_capacity, s._capacity);
		}
		/*string()
		{
			_str = new char[1];
			_str[0] = '\0';
			_capacity = _size = 0;
		}*/
		//拷贝构造传统写法
		//s2(s1)
		string(const string& s)
		{
			_str = new char[s._capacity + 1];
			_capacity = s.capacity();
			_size = s._size;
			strcpy(_str, s._str);
		}
		//拷贝构造现代写法
		//s2(s1)
		string(const string& s)
			:_str(nullptr)
			,_size(0)
			,_capacity(0)
		{
			string tmp(s._str);//构造函数
			//交换s2和tmp
			//this->swap(tmp);
			swap(tmp);
		}
		//赋值重载传统写法:
		//s1=s3
		string& operator=(const string& s)
		{
			if (this != &s)
			{
				char* tmp = new char[s._capacity + 1];
				strcpy(tmp, s._str);
				//释放s1的旧空间
				delete[] _str;
				_str = tmp;
				_size = s._size;
				_capacity = s._capacity;
			}
			return *this;
		}
		//赋值重载现代写法:
		//s1=s3
		//string& operator=(const string& s)
		//{
		//	//string tmp(s._str);
		//	string tmp(s);
		//	swap(tmp);
		//	return *this;
		//}
		//s1=s3
		string& operator=(string s)
		{
			//不用传引用传参 就用传值传参 s是s3的拷贝构造
			swap(s);
			return *this;
		}
		~string()
		{
			delete[] _str;
			_str = nullptr;
			_size = _capacity = 0;
		}
		const char* c_str() const
		{
			return _str;
		}
		size_t size() const
		{
			return _size;
		}
		size_t capacity() const
		{
			return _capacity;
		}
		//普通对象可读可写
		char& operator[](size_t pos)
		{
			assert(pos < _size);
			return _str[pos];
		}
		//const对象:只读
		const char& operator[](size_t pos) const
		{
			assert(pos < _size);
			return _str[pos];
		}
		void reserve(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)
			{
				reserve(n);
				for (size_t i = _size; i < n; ++i)
				{
					_str[i] = ch;
				}
				_size = n;
				_str[_size] = '\0';
			}
			else
			{
				_str[n] = '\0';
				_size = n;
			}
		}
		void push_back(char ch)
		{
			if (_size == _capacity)
			{
				size_t newCapacity = _capacity == 0 ? 4 : _capacity * 2;
				reserve(newCapacity);
			}
			_str[_size] = ch;
			++_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);
				_size += len;
			}
		}
		string& operator+=(char ch)
		{
			push_back(ch);
			return *this;
		}
		string& operator+=(const char* str)
		{
			append(str);
			return *this;
		}
		string& insert(size_t pos, char ch)
		{
			assert(pos <= _size);
			if (_size == _capacity)
			{
				size_t newCapacity = _capacity == 0 ? 4 : _capacity * 2;
				reserve(newCapacity);
			}
			//挪动数据
			//int end = _size;
			//操作符两边的操作数类型不一样时会发生隐式类型的提升 解决办法1:将pos强转为int
			//注意: >= 一定要强转 如果想用无符号 判断部分就不能是>=
			/*while (end >= (int)pos)
			{
				_str[end + 1] = _str[end];
				--end;
			}*/
			//解决方法2:将_str[end-1]赋值给_str[end]
			size_t end = _size + 1;
			while (end > pos)
			{
				_str[end] = _str[end - 1];
				--end;
			}
			_str[pos] = ch;
			++_size;
			return *this;
		}
		string& insert(size_t pos, const char* str)
		{
			size_t len = strlen(str);
			if (_size + len > _capacity)
			{
				reserve(_size + len);
			}
			/*int end = _size;
			while (end >= (int)pos)
			{
				_str[end + len] = _str[end];
				--end;
			}*/
			size_t end = _size + len;
			//问题:当end < len _str[end - len]存在越界 
			//while (end > pos)
			while(end >= pos + len)
			{
				_str[end] = _str[end - len];
				--end;
			}
			//使用strcpy(_str + pos,str)会拷贝\0使字符串提前结束
			strncpy(_str + pos, str, len);
			_size += len;
			return *this;
		}
		string& erase(size_t pos, size_t len = npos)
		{
			assert(pos < _size);
			if (len == npos || pos + len >= _size)
			{
				_str[pos] = '\0';
				_size = pos;
			}
			else
			{
				strcpy(_str + pos, _str + pos + len);
				_size -= len;
			}
			return *this;
		}
		size_t find(char ch, size_t pos = 0) const
		{
			assert(pos < _size);
			while (pos < _size)
			{
				if (_str[pos] == ch)
				{
					return pos;
				}
				++pos;
			}
			return npos;
		}
		size_t find(const char* str, size_t pos = 0) const
		{
			assert(pos < _size);
			const char* ptr = strstr(_str + pos, str);
			if (ptr == nullptr)
			{
				return npos;
			}
			else
			{
				return ptr -> _str;
			}
		}	
		void clear()
		{
			_size = 0;
			_str[0] = '\0';
		}
	private:
		char* _str;
		size_t _size;
		size_t _capacity;
		//const的静态整型变量可以在类中进行初始化
		const static size_t npos = -1;
	};
	ostream& operator<<(ostream& out, const string& s)
	{
		for (size_t i = 0; i < s.size(); ++i)
		{
			out << s[i];
		}
		return out;
	}
	istream& operator>>(istream& in, const string& s)
	{
		/*char ch;
		cin >> ch;
		while (ch != ' ' && ch != '\n')
		{
			s += ch;
			cin >> ch;
		}*/
		/*char ch = in.get();
		while (ch != ' ' && ch != '\n')
		{
			s += ch;
			ch = in.get();
		}*/
		//该写法不需要频繁扩容
		s.clear();
		char buff[128] = { '\0' };
		size_t i = 0;
		char ch = in.get();
		while (ch != ' ' && ch != '\n')
		{
			if (i == 127)
			{
				//满了
				s += buff;
				i = 0;
			}
			buff[i++] = ch;
			ch = in.get();
		}
		if (i >= 0)
		{
			buff[i] = '\0';
			s += buff;
		}
		return in;
	}
	void test_string1()
	{
		string s1("hello world");
		cout << s1.c_str() << endl;
		for (size_t i = 0; i < s1.size(); ++i)
		{
			s1[i]++;
		}
		cout << s1.c_str() << endl;
		string::iterator it1 = s1.begin();
		while (it1 != s1.end())
		{
			(*it1)--;
			++it1;
		}
		cout << s1.c_str() << endl;
		//范围for的原理就是迭代器
		for (auto ch : s1)
		{
			cout << ch << " ";
		}
		cout << endl;
	}
	void test_string2()
	{
		string s1("hello");
		s1 += ' ';
		s1 += "world hello world";
		cout << s1.c_str() << endl;
		string s2;
		s2 += 'x';
		cout << s2.c_str() << endl;
	}
	void test_string3()
	{
		string s1("helloworld");
		s1.insert(5, ' ');
		cout << s1.c_str() << endl;
		s1.insert(0, 'x');
		cout << s1.c_str() << endl;
		string s2("helloworld");
		cout << s2.c_str() << endl;
		s2.insert(5, " + ");
		s2.insert(0, "hello");
		cout << s2.c_str() << endl;
	}
	void test_string4()
	{
		string s1("hello hello world");
		s1.erase(0, 6);
		cout << s1.c_str() << endl;
		s1.erase(5);
		cout << s1.c_str() << endl;
	}
	void test_string5()
	{
		string s1("hello world");
		s1.resize(5);
		cout << s1.size() << endl;
		cout << s1.capacity() << endl;
		cout << s1.c_str() << endl << endl;

		string s2("hello world");
		s2.resize(15, 'x');
		cout << s2.size() << endl;
		cout << s2.capacity() << endl;
		cout << s2.c_str() << endl << endl;

		string s3("hello world");
		s3.resize(20, 'x');
		cout << s3.size() << endl;
		cout << s3.capacity() << endl;
		cout << s3.c_str() << endl << endl;
	}
	void test_string6()
	{
		string s1("hello world");
		cout << s1 << endl;
		cout << s1.c_str() << endl;

		s1.insert(5,'\0');
		cout << s1.size() << endl;
		cout << s1.capacity() << endl;

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

		cin >> s1;
		cout << s1 << endl;
	}
	void test_string7()
	{
		string s1("hello world");
		string s2(s1);
		cout << s1 << endl;
		cout << s2 << endl;
		string s3("xxxxxxxxxxxxxxxxxxxxxxxx");
		s1 = s3;
		cout << s1 << endl;
		cout << s3 << endl;
		s1.swap(s2);
		swap(s1, s2);
		//内置类型因为模板的存在 也有了构造与析构函数 
		int i(10);
		int j = int();
	}
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-05-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.构造函数
  • 2.拷贝构造函数
  • 3.赋值运算符重载
  • 4.析构函数
  • 5.string中的小接口
  • 6.operator[]的运算符重载
  • 7.迭代器
  • 8.reserve和resize
  • 9.push_back、append和+=的重载
  • 10.insert、erase和find
  • 11.<<和>>的运算符重载
  • 12.模拟实现string的整体代码
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档