string的模拟实现

发布于:2024-07-29 ⋅ 阅读:(125) ⋅ 点赞:(0)

1.成员变量和函数

1.1 成员变量

string类需要以下的成员变量:

char* _str // 一个指针,指向一个字符串
size_t _size //表示数据大小
size_t _capacity //表示可存储最大容量

1.2 函数声明

namespace cx
{
	class string
	{
	public:
		string(const char* str = "");
		~string();
		string(const string& s);

		void reserve(size_t n);

		typedef char* iterator;
		typedef const char* const_iterator;
		iterator begin();
		iterator end();	
		const_iterator begin() const;
		const_iterator end() const;


		void push_back(char ch);
		void append(const char* str);
		string& operator+=(char ch);
		string& operator+=(const char* str);
		void insert(size_t pos, char ch);
		void insert(size_t pos, const char* str);
		void erase(size_t pos=0,size_t leng=npos);



		char& operator[](size_t pos);
		const char& operator[](size_t pos) const;

		const char* c_str() const;
		size_t size() const;
		size_t capacity() const;
		void clear();
		bool empty() const;

		string substr(size_t pos = 0, size_t leng = npos) const;
		size_t find(char ch, size_t pos = 0) const;
		size_t find(const char* str, size_t pos = 0) const;
		void swap(string& s);

		bool operator<(const string& s) const;
		bool operator<=(const string& s) const;
		bool operator>(const string& s) const;
		bool operator>=(const string& s) const;
		bool operator==(const string& s) const;
		bool operator!=(const string& s) const;
		string& operator=(const string& s);

	private:
		char* _str;
		size_t _size;
		size_t _capacity;
		const static size_t  npos;
	};

	ostream& operator<<(ostream& out, const string& s);
	istream& operator>>(istream& in, string& s);
}

为了和C++标准库不冲突,可以将代码放在自己定义的命名空间内,或者类名不与库一样。

成员函数包括默认构造,拷贝构造,析构函数,运算符重载,流插入流提取的重载,增删查改已经迭代器相关的。

2.函数定义

2.1 默认成员函数

默认构造函数

//默认构造函数
string::string(const char* str)
	:_size(strlen(str))
	, _capacity(_size)
{
	_str = new char[_capacity + 1];
	strcpy(_str, str);
}

函数参数为一个指针,用于初始化对象。在申请空间时,多申请一个是因为要存储 ‘/0’。
函数声明的缺省值为"",空字符串。不能是空字符。

拷贝构造和赋值重载

//赋值运算符重载
string& string::operator=(const string& s)
{
	char* tmp = new char[s._capacity + 1];
	strcpy(tmp, s._str);
	delete[] _str;
	_str = tmp;
	_capacity = s._capacity;
	_size = s._size;
	return *this;
}

//拷贝构造函数
string::string(const string& s)
{
    _str = new char[s._capacity+1];
	strcpy(_str, s._str);
	_capacity = s._capacity;
	_size = s._size;
}

析构函数

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

2.2 增删查改


包括insert(任意位置插入字符或字符串)append(追加字符或字符串)push_back(尾插字符)。

//尾插
void string::push_back(char ch)
{
	if (_size == _capacity)
	{
		size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
		char* tmp = new char[newcapacity + 1];
		strcpy(tmp, _str);
		delete[] _str;
		_str = tmp;
		_capacity = newcapacity;
	}
	_str[_size++] = ch;
	_str[_size] = '\0';
}

//追加字符串
void string::append(const char* str)
{
	size_t leng = strlen(str);
	if (_size + leng >= _capacity)
	{
		size_t newcapacity = _capacity == 0 ? leng : _capacity + leng;
		char* tmp = new char[newcapacity + 1];
		strcpy(tmp, _str);
		delete[] _str;
		_str = tmp;
		_capacity = newcapacity;
	}
	strcat(_str + _size, str);
	_size += leng;
}
	// pos位置插入字符和字符串
void string::insert(size_t pos,char ch)
{
	assert(pos <= _size);

	if (_size == _capacity)
	{
		size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
		reserve(newcapacity);
	}
	size_t end = _size + 1;
	while (end > pos)
	{
		_str[end] = _str[end - 1];
		--end;
	}
	_str[pos] = ch;
	++_size;
}
void string::insert(size_t pos, const char* str)
{
	assert(pos <= _size);
	size_t leng = strlen(str);
	if (_size+leng>_capacity)
	{
		size_t newcapacity = _capacity == 0 ? leng : _capacity + leng;
		reserve(newcapacity);
	}
	size_t end = _size + leng;
	while (end>=pos+leng)
	{
		_str[end] = _str[end - leng];
		--end;
	}
	strncpy(_str + pos, str, leng);
	_size += leng;
}
// += 运算符重载
string& string::operator+=(char ch)
{
	this->push_back(ch);
	return *this;
}
string& string::operator+=(const char* str)
{
	this->append(str);
	return *this;
}

// pos位置删除leng个字符
void string::erase(size_t pos, size_t leng)
{
	assert(pos <= _size);
	if (leng > _size - pos)
	{
		_str[pos] = '\0';
		_size = pos;
	}
	else
	{
		strcpy(_str + pos, _str + pos + leng);
		_size -= leng;
	}
}

其中pos和leng可以不传参数,缺省值分别为0和npos,npos为类内的一个静态成员变量。类型为const size_t 初始化值为-1,表示整型的最大值。若不传第二个参数,表示从pos开始删除后面的全部字符。

//查找字符和字符串
size_t string::find(char ch, size_t pos) const
{
	for (size_t i = pos; i < _size; ++i)
	{
		if (_str[i] == ch)
		{
			return i;
		}
	}
	return npos;
}
size_t string::find(const char* str, size_t pos) const
{
	char* sub = strstr(_str + pos, str);
	return sub - _str;
}

	// [ ] 运算符重载
	char& string::operator[](size_t pos)
	{
		return _str[pos];
	}
	const char& string::operator[](size_t pos) const
	{
		return _str[pos];
	}
	const char* string::c_str() const
	{
		return _str;
	}

其他函数
包括交换函数,容量相关,运算符重载等。

//容量和大小
size_t string::size() const
{
	return _size;
}
size_t string::capacity() const
{
	return _capacity;
}

//交换
void string::swap(string& s)
{
	std::swap(_str, s._str);
	std::swap(_size, s._size);
	std::swap(_capacity, s._capacity);
}

//运算符重载
bool string::operator<(const string& s) const
{
	return strcmp(_str, s._str) < 0;
}
bool string::operator<=(const string& s) const
{
	return (*this < s) || (*this == s);
}
bool string::operator>(const string& s) const
{
	return !(*this <= s);
}
bool string::operator>=(const string& s) const
{
	return !(*this < s);
}
bool string::operator==(const string& s) const
{
	return strcmp(_str, s._str) == 0;
}
bool string::operator!=(const string& s) const
{
	return !(*this == s);
}

//流插入、流提取
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, string& s)
{
	s.clear();
	char ch;
	ch = in.get();
	while (ch != ' ' && ch != '\n')
	{
		s += ch;
		ch = in.get();
	}
	return in;
}

//扩容
void string::reserve(size_t n)
{
	if (n > _capacity)
	{
		char* tmp = new char[n + 1];
		strcpy(tmp, _str);
		delete[] _str;
		_str = tmp;
		_capacity = n;
	}
}

迭代器相关
在string中,迭代器就是一个char*的指针。

typedef char* iterator;
typedef const char* const_iterator;

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

3.完整代码

string.h

#pragma once
#include<iostream>
#include<assert.h>
using namespace std;

namespace cx
{
	class string
	{
	public:
		
		string(const char* str = "");
		~string();
		string(const string& s);

		void reserve(size_t n);

		typedef char* iterator;
		typedef const char* const_iterator;

		iterator begin();
		iterator end();	
		const_iterator begin() const;
		const_iterator end() const;


		void push_back(char ch);
		void append(const char* str);
		string& operator+=(char ch);
		string& operator+=(const char* str);
		void insert(size_t pos, char ch);
		void insert(size_t pos, const char* str);
		void erase(size_t pos=0,size_t leng=npos);



		char& operator[](size_t pos);
		const char& operator[](size_t pos) const;

		const char* c_str() const;
		size_t size() const;
		size_t capacity() const;
		void clear();
		bool empty() const;

		string substr(size_t pos = 0, size_t leng = npos) const;
		size_t find(char ch, size_t pos = 0) const;
		size_t find(const char* str, size_t pos = 0) const;
		void swap(string& s);

		bool operator<(const string& s) const;
		bool operator<=(const string& s) const;
		bool operator>(const string& s) const;
		bool operator>=(const string& s) const;
		bool operator==(const string& s) const;
		bool operator!=(const string& s) const;
		string& operator=(const string& s);

	private:
		char* _str;
		size_t _size;
		size_t _capacity;
		const static size_t  npos;
	};

	ostream& operator<<(ostream& out, const string& s);
	istream& operator>>(istream& in, string& s);
}

string.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include"string.h"

namespace cx
{
	const size_t string::npos=-1;
	
	//默认构造函数
	string::string(const char* str)
		:_size(strlen(str))
		, _capacity(_size)
	{
		_str = new char[_capacity + 1];
		strcpy(_str, str);
	}

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

	//拷贝构造函数
	string::string(const string& s)
	{
	    _str = new char[s._capacity+1];
		strcpy(_str, s._str);
		_capacity = s._capacity;
		_size = s._size;
	}

	// [ ] 运算符重载
	char& string::operator[](size_t pos)
	{
		return _str[pos];
	}
	const char& string::operator[](size_t pos) const
	{
		return _str[pos];
	}
	const char* string::c_str() const
	{
		return _str;
	}

	//容量和大小
	size_t string::size() const
	{
		return _size;
	}
	size_t string::capacity() const
	{
		return _capacity;
	}

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

	//扩容
	void string::reserve(size_t n)
	{
		if (n > _capacity)
		{
			char* tmp = new char[n + 1];
			strcpy(tmp, _str);
			delete[] _str;
			_str = tmp;
			_capacity = n;
		}
	}

	//尾插
	void string::push_back(char ch)
	{
		if (_size == _capacity)
		{
			size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
			char* tmp = new char[newcapacity + 1];
			strcpy(tmp, _str);
			delete[] _str;
			_str = tmp;
			_capacity = newcapacity;
		}
		_str[_size++] = ch;
		_str[_size] = '\0';
	}

	//追加字符串
	void string::append(const char* str)
	{
		size_t leng = strlen(str);
		if (_size + leng >= _capacity)
		{
			size_t newcapacity = _capacity == 0 ? leng : _capacity + leng;
			char* tmp = new char[newcapacity + 1];
			strcpy(tmp, _str);
			delete[] _str;
			_str = tmp;
			_capacity = newcapacity;
		}
		strcat(_str + _size, str);
		_size += leng;
	}

	// += 运算符重载
	string& string::operator+=(char ch)
	{
		this->push_back(ch);
		return *this;
	}
	string& string::operator+=(const char* str)
	{
		this->append(str);
		return *this;
	}

	//清空、判空
	void string::clear()
	{
		_str[0] = '\0';
		_size = 0;
	}
	bool string::empty() const
	{
		return _size == 0;
	}

	// pos位置插入字符和字符串
	void string::insert(size_t pos,char ch)
	{
		assert(pos <= _size);

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

	// pos位置删除leng个字符
	void string::erase(size_t pos, size_t leng)
	{
		assert(pos <= _size);
		if (leng > _size - pos)
		{
			_str[pos] = '\0';
			_size = pos;
		}
		else
		{
			strcpy(_str + pos, _str + pos + leng);
			_size -= leng;
		}
	}

	//获取字串
	string string::substr(size_t pos, size_t leng) const
	{
		assert(pos <= _size);
		
		if (leng > _size - pos)
		{
			string sub(_str + pos);
			return sub;
		}
		else
		{
			string sub;
			sub.reserve(leng);
			for (size_t i = pos; i < pos + leng; i++)
			{
				sub += _str[i];
			}
			return sub;
		}
	}

	//查找字符和字符串
	size_t string::find(char ch, size_t pos) const
	{
		for (size_t i = pos; i < _size; ++i)
		{
			if (_str[i] == ch)
			{
				return i;
			}
		}
		return npos;
	}
	size_t string::find(const char* str, size_t pos) const
	{
		char* sub = strstr(_str + pos, str);
		return sub - _str;
	}

	//交换
	void string::swap(string& s)
	{
		std::swap(_str, s._str);
		std::swap(_size, s._size);
		std::swap(_capacity, s._capacity);
	}

	//运算符重载
	bool string::operator<(const string& s) const
	{
		return strcmp(_str, s._str) < 0;
	}
	bool string::operator<=(const string& s) const
	{
		return (*this < s) || (*this == s);
	}
	bool string::operator>(const string& s) const
	{
		return !(*this <= s);
	}
	bool string::operator>=(const string& s) const
	{
		return !(*this < s);
	}
	bool string::operator==(const string& s) const
	{
		return strcmp(_str, s._str) == 0;
	}
	bool string::operator!=(const string& s) const
	{
		return !(*this == s);
	}

	//流插入、流提取
	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, string& s)
	{
		s.clear();
		char ch;
		ch = in.get();
		while (ch != ' ' && ch != '\n')
		{
			s += ch;
			ch = in.get();
		}
		return in;
	}

	//赋值运算符重载
	string& string::operator=(const string& s)
	{
		char* tmp = new char[s._capacity + 1];
		strcpy(tmp, s._str);
		delete[] _str;
		_str = tmp;
		_capacity = s._capacity;
		_size = s._size;
		return *this;
	}
}

test.cpp

用于检测函数是否由bug

#define _CRT_SECURE_NO_WARNINGS 1
#include"string.h"

namespace cx
{
	void test_string1()
	{
		cx::string s = ("We are born ceaselessly into the future");
		cout << s.size() << " " << s.capacity() << " " << endl;
		cout << s.c_str() << endl;
	}

	void test_string2()
	{
		cx::string s = ("We are born ceaselessly into the future");
		for (int i = 0; i < s.size(); i++)
		{
			//s[i]++;
			cout << s[i];
		}
		cout << endl;

		string::iterator it = s.begin();
		while (it != s.end())
		{
			cout << *it;
			it++;
		}
		cout << endl;
		
		cx::string s1 = "12345689";
		string::const_iterator it1 = s1.begin();
		while (it1 != s1.end())
		{
			cout << *it1;
			++it1;
		}
		cout << endl;

		for (auto ch : s)
		{
			cout << ch;
		}
		cout << endl;
	}

	void test_string3()
	{
		cx::string s = "We are born ceaselessly into the future";
		cx::string s1(s);
		cout << s1.c_str() << endl;

		cx::string s2;
		for (int i = 0; i < 33; i++)
		{
			s2.push_back(i+'0');
			if (s2.size() == s2.capacity())
				cout << s2.capacity() << endl;
		}
		cout << s2.c_str();
	}

	void test_string4()
	{
		cx::string s;
		s.append("1");
		s.append("10000");
		cout << s.c_str() << endl;

		s += 'a';
		s += 'a';
		s += 'a';
		s += 'a';
		s += 'a';
		cout << s.c_str() << endl;

		s += "101";
		s += "101";
		s += "101";
		s += "101";
		s += "101";
		cout << s.c_str() << endl;
	}

	void test_string5()
	{
		cx::string s;
		s.insert(0, '0');
		s.insert(0, '0');
		s.insert(0, '0');
		s.insert(0, '0');
		s.insert(0, '0');
		s.insert(5, '1');
		s.insert(3, '2');

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

		cx::string s1;
		s1.insert(0, "00");
		s1.insert(1, "00");
		s1.insert(0, "00");
		s1.insert(0, "00");
		s1.insert(3, "111");
		cout << s1.c_str() << endl;
	}

	void test_string6()
	{
		cx::string s="123456789";
		s.erase(6);
		cout << s.c_str() << endl;
		s.erase();
		cout << s.c_str() << endl;
	}
	void test_string7()
	{
		cx::string s = "123456789";
		cx::string sub1=s.substr(5);
		cout << sub1.c_str() << endl;
	}

	void test_string8()
	{
		cx::string s = "123456789";
		s.insert(s.find('5'), '0');
		cout << s << endl;

		cout << s.find("789",3) << endl;
		string s1;
		cin >> s1;
		cout << s1;
	}

	void test_string9()
	{
		cx::string s = "123456789";
		string sub;
		sub = s.substr(3);
		cout << sub;
	}
}



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

网站公告

今日签到

点亮在社区的每一天
去签到