STL string的主要接口模拟实现

string 是什么

string通俗来说就是一个支持增删查改功能的字符串
特点
动态大小:string对象的大小可以在运行时动态改变,可以添加或删除字符而不用担心固定大小的限制。
方便的操作:提供了大量成员函数来执行常见的字符串操作,如查找、替换、拼接等。
安全性:string类处理了内存管理,减少了缓冲区溢出和内存泄漏的风险。
兼容性:与C风格的字符串(以空字符’\0’结尾的字符数组)兼容。
下面我们来说说模拟实现,这里我们模拟实现string统称mystring
首先看看构造函数

构造函数

	//默认构造
	mystring(const char* str = "")
	{
		_size = strlen(str);
		_capacity = _size;
		_str = new  char[_capacity + 1];//给\0开空间
		strcpy(_str, str);
	}

这里我们的参数给了一个缺省参数,缺省值是一个空字符串,size代表string中存放数据的个数(不包括\0),capacity代表string总共空间大小,最后在调用库函数的strcpy(字符串拷贝函数)把输入的字符串拷贝到我们的string里面的_str里去。
在这里插入图片描述

拷贝构造函数

//拷贝构造
mystring(const mystring& str)
{
	this->_size = str._size;
	this->_capacity = str._capacity;
	this->_str = new char[str._capacity + 1];
	strcpy(_str,str._str);
}

这里我们必须要写拷贝构造函数,因为我们申请了空间,不能调用编译器默认的拷贝构造函数,我们需要对拷贝创建的对象新开一个内存空间,这样两个mystring的对象的内存地址才不会犯冲突,最后在调用字符串拷贝函数拷贝过来就可以了

析构函数

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

这里直接调用delete函数,把mystring类里面的_str指向的内存空间给释放掉,在把这个指针指向空,最后把_size,_capacity设置成0就行了

迭代器的实现

迭代器的本质上就是一个指针,我们这里可以直接用原生指针,因为string和vector一样,他们的内存地址都是连续的,不需要像list那样自己手动实现一个迭代器(通过返回当前节点指向的下一个节点实现++功能等),
我们需要typedef一下我们的迭代器

typedef char* iterator;
typedef const char* const_iterator;

为什么typedef const char* const_iterator;不能直接写成const iterator,这是因为,const iterator,这个const是修饰iterator本身,假设这个iterator是个指针,const就修饰的是这个iterator指针变量的本身,而不是这个指针所指向的对象,所以要重新定义一下

//迭代器的实现
	iterator begin()
	{
		return _str;
	}
	iterator end()
	{
		return _str+_size;
	}
	const_iterator begin() const
	{
		return _str;
	}
	const_iterator end() const
	{
		return _str + _size;
	}

begin()返回头指针,end()通过对头指针的向后计算,计算出相应的尾指针。还有const修饰版本

申请空间

	void reserve(size_t n)//申请空间
	{
		char* temp = nullptr;
		if (n > _capacity)
		{
			 temp = new char[n + 1];//为\0申请多一个
		}
		strcpy(temp, _str);
		delete[] _str;
		_str = temp;
		_capacity = n;
	}

这里我们首先要创建一个临时变量temp用来存放我们新开的空间,然后在把原来string里面的数据拷贝到新的空间里面去,最后在删除原来的空间,把temp给给_str,更新一下总共大小(capacity)

尾插

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

这里首先要判断空间是否足够我们插入,如果不够就按照2倍扩容,扩完之后直接在后面插入即可(_size指向存放元素的下一个空间,因为是从0地址开始存放的5个数据占用0-4个空间)插入完之后更新size在放置\0即可

插入(单字符,字符串)

插入单字符

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

这个代表在指定pos位置插入单个字符,我们需要一个end来把整个字符串向后面移动一位,把pos位置给腾出来,在往里面插入,最后更新一下size即可
在这里插入图片描述

插入字符串

//插入字符串
void insert(size_t pos, const char* str)
{
	assert(pos <=_size);
	size_t len = strlen(str);
	if (_size + len >= _capacity)
	{
		reserve(_size +len>2*_capacity ? _size + len : 2 * _capacity);
	}
	size_t end = _size + len;
	while (end > pos+len-1)
	{
		_str[end] = _str[end - len];
		end--;
	}
	for (int i = 0; i < len; i++)
	{
		_str[pos+i] = str[i];
	}
	_size = _size + len;
}

插入字符串相较于插入单字符要难一些,同样这里考虑扩容的方式还是2倍的方式,只不过先考虑_size+len大不大于 2倍当前内存空间,这里要分两步,第一步是把pos到len的空间给移动出来,第二步才是从pos位置开始插入
在这里插入图片描述

删除

//删除
void erase(size_t pos, size_t len)
{
	assert(pos < _size);
	if (len > _size - len)
	{
		_str[pos] = '\0';
		_size = pos;
	}
	for (size_t i = pos + len; i <= _size; i++)
	{
		_str[i - len] = _str[i];
	}
	_size -= len;
}

这里代表从pos位置开始向后面删除len个长度的字符串,这个if条件代表如果想从pos位置后面删除的数据长度超过了总共数据长度的话,就全部删除,这个就很简单,直接把pos位置置为\0(字符串结束标志)就行了
如果不是就要像上面那样,循环去删除,这里i等于size是为了把字符串结尾的\0也一同搬过去,最后就在更新一下size就行了

查找(字符,字符串)

查找字符

//查找
size_t find(char ch,size_t pos)
{
	assert(pos < _size);
	for (size_t i = 0; i < _size; i++)
	{
		if (i == pos)
		{
			if (_str[i] == ch)
			{
				return i;
				break;
			}
		}
	}
	return npos;
}

这个就简单,直接循环查找,有的话就返回当前字符的下标,如果没有就返回nops

查找字符串

//查找字符串
size_t find(const char* str, size_t pos)
{
	assert(pos < _size);
	char* ptr = strstr(_str + pos, str);
	if (ptr == nullptr)
	{
		return npos;
	}
	else
	{
		return ptr - _str;
	}
}

这里我们用了一个比较两个字符串的库函数,如果比较成功就返回比较的字符串的起始地址,如果比较失败就直接返回空指针返回npos就可以了,如果比较成功了,就返回当前匹配成功字符串的首地址

添补append

	//添补
	void append(const char* str)
	{
		size_t len = strlen(str);

		if (_size + len >= _capacity)
		{
			reserve(_size + len > 2 * _capacity ? _size + len : 2 * _capacity);
		}
		strcpy(_str + _size, str);
		_size = _size + len;
	}

这个函数和push_back很像,这个是在字符串尾部插入一个字符串,首先检查空间,不够的话扩容,之后在调用字符串拷贝函数,把要添加的字符串添加到string中,最后更新一下大小

字符串+=

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

一个是+=一个字符,就直接调用push_back一个是+=一串字符串,就调用append函数,最后返回this指针

substr

		mystring substr(size_t pos, size_t len)
		{
			assert(pos < _size);
			mystring sub;
			if (len > _size - pos)
			{
				len = _size - pos;
			}
			for (size_t i = 0; i < len; i++)
			{
				sub.operator+=(_str[pos+i]);
			}
			return sub;
		}

这个代表将原string中的从pos位置向后len个长度的字符串拷贝到一个新的string对象中去
同样,我们首先需要判断他的长度大不大于_size-pos大于就全部拷贝过去,最后一个for循环来进行拷贝调用运算符重载+=函数

赋值重载

	void swap(mystring& inputstr)
	{
		std::swap(_str, inputstr._str);
		std::swap(_size, inputstr._size);
		std::swap(_capacity, inputstr._capacity);
	}
	//赋值重载
	mystring& operator=(mystring inputstr)
	{
		swap(inputstr);
		return *this;
	}

这里我们处理赋值,很巧妙用了一个swap函数,来交换两个string对象指向的空间,就假设把s2赋值给s1就交换他们的空间大小,指针指向的字符串。因为这里是值传递,假设把s2赋值给s1,当函数结束后s2在swap函数里面就会销毁,s1变成s2

c_str

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

返回一个字符串,像c语言一样

[ ]下标访问

	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];
	}

运算符重载

bool operator<(const string& s1, const string& s2)
{
	return strcmp(s1.c_str(), s2.c_str()) < 0;
}
bool operator>(const string& s1, const string& s2)
{
	return !(strcmp(s1.c_str(), s2.c_str()) < 0);
}
bool operator==(const string& s1, const string& s2)
{
	return strcmp(s1.c_str(), s2.c_str()) == 0;
}
bool operator>=(const string& s1, const string& s2)
{
	return operator==(s1, s2) || operator>(s1, s2);
}
bool operator<=(const string& s1, const string& s2)
{
	return operator==(s1, s2) || operator<(s1, s2);
}
bool operator!=(const string& s1, const string& s2)
{
	return !operator==(s1, s2);
}

这里主要调用库函数的比较

流插入

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

把str里面的内容插入到out里

流提取

istream& operator>>(istream& in,mystring& str)
{
	str.clear();
	const int N = 256;
	char buffer[N] = { 0 };
	size_t i = 0;
	char ch = 0;
	ch = in.get();
	while (ch != ' ' && ch != '\n')
	{
		buffer[i++] = ch;
		if (i == N - 1)
		{
			buffer[i] = '\0';
			str += buffer;
			i = 0;
		}
		ch = in.get();
	}
	if (i > 0)
	{
		buffer[i] = '\0';
		str += buffer;
	}
	return in;
}

这里主要是把io流里面输入的字符串插入到str中去,这里我们用了一个buffer缓存来临时存放要插入的数据,这样为了减少内存频繁插入,节省时间的消耗不会一个字符一个字符的提取。

源码

#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
# include<iostream>
# include<string>
# include<assert.h>
using namespace std;
namespace thr
{
	class mystring
	{
	public:
		typedef char* iterator;
		typedef const char* const_iterator;
		//默认构造
		mystring(const char* str = "")
		{
			_size = strlen(str);
			_capacity = _size;
			_str = new  char[_capacity + 1];//给\0开空间
			strcpy(_str, str);
		}
		//拷贝构造
		mystring(const mystring& str)
		{
			this->_size = str._size;
			this->_capacity = str._capacity;
			this->_str = new char[str._capacity + 1];
			strcpy(_str,str._str);
		}
		//析构函数
		~mystring()
		{
			delete[] _str;
			_str = nullptr;
			_size = 0;
			_capacity = 0;
		
		}
		iterator begin()
		{
			return _str;
		}
		iterator end()
		{
			return _str+_size;
		}
		const_iterator begin() const
		{
			return _str;
		}
		const_iterator end() const
		{
			return _str + _size;
		}
		size_t size()
		{
			return _size;
		}
		size_t capacity()
		{
			return _capacity;
		}
		const char* c_str() const
		{
			return _str;
		}
		void clear()
		{
			_str[0] = '\0';
			_size = 0;
		}
		char& operator[](size_t pos)
		{
			assert(pos < _size);

			return _str[pos];
		}

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

			return _str[pos];
		}
		//尾插
		void push_back(char ch)
		{
			if (_size == _capacity)
			{
				reserve(_capacity == 0 ? 4 : 2 * _capacity);
			}
			_str[_size] = ch;
			_size++;
			_str[_size] = '\0';
		}
		void reserve(size_t n)//申请空间
		{
			char* temp = nullptr;
			if (n > _capacity)
			{
				 temp = new char[n + 1];
			}
			strcpy(temp, _str);
			delete[] _str;
			_str = temp;
			_capacity = n;
		}
		void swap(mystring& inputstr)
		{
			std::swap(_str, inputstr._str);
			std::swap(_size, inputstr._size);
			std::swap(_capacity, inputstr._capacity);
		}
		//赋值重载
		mystring& operator=(mystring inputstr)
		{
			swap(inputstr);
			return *this;
		}
		//插入单个字符
		void insert(size_t pos, char ch)
		{
			assert(pos<=_size);
			if (_size == _capacity)
			{
				reserve(_capacity == 0?4:2*_capacity);
			}
			size_t end = _size + 1;
			while (end > pos)
			{
			 _str[end] = _str[end-1];
			end--;
			}
			_str[pos] = ch;
			_size++;
		}
		//打印
		void print()
		{
			cout <<"size:" << _size << endl;
			cout <<"capacity:" << _capacity << endl;
			cout <<"_str:"<< _str << endl;
			cout << endl;
		}
		//插入字符串
		void insert(size_t pos, const char* str)
		{
			assert(pos <=_size);
			size_t len = strlen(str);
			if (_size + len >= _capacity)
			{
				reserve(_size +len>2*_capacity ? _size + len : 2 * _capacity);
			}
			size_t end = _size + len;
			while (end > pos+len-1)
			{
				_str[end] = _str[end - len];
				end--;
			}
			for (int i = 0; i < len; i++)
			{
				_str[pos+i] = str[i];
			}
			_size = _size + len;
		}
		//删除
		void erase(size_t pos, size_t len)
		{
			assert(pos < _size);
			if (len > _size - len)
			{
				_str[pos] = '\0';
				_size = pos;
			}
			for (size_t i = pos + len; i <= _size; i++)
			{
				_str[i - len] = _str[i];
			}
			_size -= len;
		}
		//查找
		size_t find(char ch,size_t pos)
		{
			assert(pos < _size);
			for (size_t i = 0; i < _size; i++)
			{
				if (i == pos)
				{
					if (_str[i] == ch)
					{
						return i;
						break;
					}
				}
			}
			return npos;
		}
		//查找字符串
		size_t find(const char* str, size_t pos)
		{
			assert(pos < _size);
			char* ptr = strstr(_str + pos, str);
			if (ptr == nullptr)
			{
				return npos;
			}
			else
			{
				return ptr - _str;
			}
		}
		//添补
		void append(const char* str)
		{
			size_t len = strlen(str);

			if (_size + len >= _capacity)
			{
				reserve(_size + len > 2 * _capacity ? _size + len : 2 * _capacity);
			}
			strcpy(_str + _size, str);
			_size = _size + len;
		}
		mystring& operator+=(char ch)
		{
			push_back(ch);
			return *this;
		}
		mystring& operator+=(const char* str)
		{
			append(str);
			return *this;
		}
		mystring substr(size_t pos, size_t len)
		{
			assert(pos < _size);
			mystring sub;
			if (len > _size - pos)
			{
				len = _size - pos;
			}
			for (size_t i = 0; i < len; i++)
			{
				sub.operator+=(_str[pos+i]);
			}
			return sub;
		}
	private:
		char* _str = nullptr;
		size_t _size = 0;
		size_t _capacity = 0;
		static const size_t npos = -1;
	};

	bool operator<(const string& s1, const string& s2)
	{
		return strcmp(s1.c_str(), s2.c_str()) < 0;
	}
	bool operator>(const string& s1, const string& s2)
	{
		return !(strcmp(s1.c_str(), s2.c_str()) < 0);
	}
	bool operator==(const string& s1, const string& s2)
	{
		return strcmp(s1.c_str(), s2.c_str()) == 0;
	}
	bool operator>=(const string& s1, const string& s2)
	{
		return operator==(s1, s2) || operator>(s1, s2);
	}
	bool operator<=(const string& s1, const string& s2)
	{
		return operator==(s1, s2) || operator<(s1, s2);
	}
	bool operator!=(const string& s1, const string& s2)
	{
		return !operator==(s1, s2);
	}
	ostream& operator<<(ostream& out, const mystring& str)
	{
		for (auto ch:str)
		{
			out << ch;
		}
	  return out;
	}

	istream& operator>>(istream& in,mystring& str)
	{
		str.clear();
		const int N = 256;
		char buffer[N] = { 0 };
		size_t i = 0;
		char ch = 0;
		ch = in.get();
		while (ch != ' ' && ch != '\n')
		{
			buffer[i++] = ch;
			if (i == N - 1)
			{
				buffer[i] = '\0';
				str += buffer;
				i = 0;
			}
			ch = in.get();
		}
		if (i > 0)
		{
			buffer[i] = '\0';
			str += buffer;
		}
		return in;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值