string类模拟实现

前言:今天我们用C++实现一个增删查改的string类

1.构造,拷贝构造,析构

定义私有成员变量:

	private:
		char* _str;
		size_t _size; //已经有多少个有效字符
		size_t _capacity; //能存多少个有效字符
		static size_t npos;

1.1实现构造函数

		string(const char* str="")
		{
			_size = strlen(str);
			_capacity = _size; // '\0'不是有效字符
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}
//string(const char* str = "\0") 错误示范
//string(const char* str = nullptr) 错误示范

1.2 拷贝构造

深浅拷贝问题

浅拷贝,也称值拷贝,编译器只是将对象中的值拷贝过来,会出现多个对象共用同一份资源,当一个对象将那份空间释放掉,另一个对象不知道的时候会出现错误访问。

浅拷贝的问题:1.同一块空间会被析构两次  2.其中一个修改数据会影响另一个

string(const string& s)
    :_str(new char[strlen(s._str)+1])
    ,_size(0)
    ,_capacity(0)
{
    strcpy(_str,s._str);
    _size = s._size;
    _capacity = s._capacity;
}

1.3 析构函数 

		~string()
		{
			delete[] _str;
			_str = nullptr; //释放后记得置空
			_capacity = _size = 0;
		}

2.运算符重载 

当我们想比较两个string类的大小时,内置的运算符不适用,因此我们将自己实现运算符重载

由于运算符重载比较简单,不做过多阐述,直接将实现的代码写上

2.1  s1<s2

bool operator<(const string& s)
{
	int ret = strcmp(_str, s._str); //比较两个字符串大小,比较ASII码值
	return ret < 0;
}

2.2  s1==s2

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

2.3 s1<=s2

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

2.4 s1>s2 

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

2.5 s1>=s2 

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

2.6 s1!=s2 

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

 3.增删查改

由于我们会在类外面遍历数组之类等操作会用到_size,_capacity,_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 char& operator[](size_t pos) const
{
	assert(pos < _size);
	return _str[pos];
}
const char* c_str()
{
	return _str;
}

3.1 增加一个字符或者字符串 

插入的时候可能会出现空间不够的时候,因此我们要增容,由于经常会使用增容,防止出现代码冗长,因此我们将增容用一个函数实现,方便调用。

void reserve(size_t n)
{
	if (n > _capacity)
	{
		char* newstr = new char[n + 1];
		strcpy(newstr, _str);
		delete[] _str;
		_str = newstr;
		_capacity = n;
	}

}

push_back :尾插一个字符 

void push_back(char ch)
{
	if (_size == _capacity) //判断是否需要增容
	{
		size_t newcapacity =_capacity == 0 ? 2 : _capacity * 2;
		reserve(newcapacity);
	}
	_str[_size] = ch;
	_size++;
	_str[_size] = '\0'; //必须加一个\0 ,否则出现内存泄露
}

append : 尾插字符串

void append(const char* str)
{
	size_t len = strlen(str);
	if (_size + len > _capacity)
	{
		size_t newcapacity = _size + len;
		reserve(newcapacity);
	}
	strcpy(_str+_size, str);
	_size += len;
}

 由于插入字符和字符串会用到两个不同的函数,因此为了方便我们用"+="来实现

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

上述代码可以看出“+=”的底层实现仍然是调用push_back和append

3.2 删除 

 从pos位置,删除len长度的字符

void erase(size_t pos, size_t len = npos)
{
	if (len >= _size - pos) //判断是否删除pos位置后所有字符
	{
		_str[pos] = '\0';
		_size  = pos;
	}
	else
	{
		while (pos <= _size)
		{
			_str[pos]  = _str[pos + len];
			pos++;
		}
		_size -= len;
	}

}

3.3 查找

 在已知的字符串从pos位置查找所需要的字符或者字符串,返回它的位置,没知道则返回-1

size_t find(char ch, size_t pos = 0)
{
	for (size_t i = pos;i < _size; i++)
	{
		if (_str[i] == ch)
		{
			return i;
		}
	}
	return npos;
}
size_t find(const char* str, size_t pos = 0)
{
	char* p = strstr(_str, str); //寻找字符串里的子串
	if (p == nullptr)
	{
		return npos;
	}
	else
		return p - _str; //两个指针之间的个数
}

3.4 插入 

在pos位置插入一个字符或者字符串

void insert(size_t pos, char ch)
{
	if (_size == _capacity)
	{
		size_t newcapacity = _capacity == 0 ? 2 : _capacity * 2;
		reserve(newcapacity);
	}
	size_t end = _size;
	while (end >= pos)
	{
		_str[end + 1] = _str[end];
		end--;
	}
	_str[pos] = ch;
	_size++;
}
void insert(size_t pos, const char* str)
{
	size_t len = strlen(str);
	if (_size + len > _capacity)
	{
		size_t newcapacity = _size + len;
		reserve(newcapacity);
	}
	size_t end = _size;
	while (end >= pos)
	{
		_str[end + len] = _str[end];
		end--;
	}
	for (size_t i = 0; i < len; i++)
	{
		_str[pos++] = str[i];
	}
	_size += len;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值