0
点赞
收藏
分享

微信扫一扫

string的模拟实现

非衣所思 2022-03-19 阅读 40
c++

📌string的模拟实现

😊本文为小碗里原创,CSDN首发
📅发布时间:2002/3/19
🙌欢迎大家👍点赞❤收藏✨加关注
✒本文大约3100词左右
🙏笔者水平有限,如有错误,还望告诉笔者,万分感谢!
🚩有什么问题也可在评论区一起交流哦!

文章目录

🎉前言

🎉模拟实现

👂一.主干结构

#include<iostream>
//平时练习可以全部展开,命名污染可忽略
using namespace std;

//自己模拟实现的string要与标准库里的string区别
//故模拟实现的string放在自己的命名空间
namespace S
{
	class string
	{
	public:
        //成员函数
	private:
	    //成员变量
		char* _str;    //字符串
		int _size;     //当前有效字符个数(不含'\0')
		int _capacity; //有效字符容量(不含'\0')
    public:
        static const size_t npos = -1;
        //const修饰的静态的成员变量可以在类里给缺省值
        //但非const修饰的成员变量只能在类外初始化
	};
}

👂二.成员函数

🥩系列一

1.构造函数
string(const char* str = "")//默认缺省值为'\0'
			:_str(nullptr), _size(strlen(str)), _capacity(_size)
		{
			_str = new char[_capacity + 1];//为'\0'多开一个空间
			strcpy(_str, str);
		}
2.析构函数
~string()
		{
            //当_str不为nullptr时释放空间
			if (_str)
			{
				delete[] _str;
				_str = nullptr;
				_size = _capacity = 0;
			}
		}
3.拷贝构造函数(深拷贝)
//写法一:1.0版本
string(const string& s)
			:_str(nullptr), _size(s._size), _capacity(s._capacity)
		{
			_str = new char[_capacity + 1];//为'\0'多开一个空间
			strcpy(_str, s._str);
		}

//写法二:2.0版本(分析如下图)
string(const string& s)
			:_str(nullptr),_size(s._size),_capacity(s._capacity)
                //_str必须初始化为nullptr
		{
            //复用构造函数开空间,且tmp为局部变量,之后有析构函数销毁
			string tmp(s._str);
			std::swap(_str, tmp._str);
		}
//这里也可用我们自己实现的swap成员函数,它的定义在下文给出
//写法三:
string(const string& s)
			:_str(nullptr), _size(0), _capacity(0)
		{
			string tmp(s._str);
			swap(tmp);
		}

在这里插入图片描述

图 1 图1 1

4.赋值运算符重载
//写法一:1.0版本
string& operator=(const string& s)
		{
			if (this != &s)//避免自己给自己赋值
			{
				int len = strlen(s._str);
                //避免new抛异常,而_str却被释放
			    char* tmp = new char[len + 1];
				strcpy(tmp, s._str);
				delete[] _str;
				_str = tmp;
				_capacity = _size = len;
			}
            //函数调用完成后,*this没有被销毁,故采用引用返回,减少拷贝
			return *this;
		}

也许你们的写法如下:

string& operator=(const string& s)
		{
			if (this != &s)
			{
				int len = strlen[s._str];
                //假如new失败了,既没有开新的空间,还把_str释放了
				delete[] _str;
				_str = new char[len + 1];
				strcpy(_str, s._str);
				_capacity = _size = len;
			}
			return *this;
		}

细节决定成败…

//写法二:2.0版本(分析如图2)
string& operator=(string s)//注意,这里不是引用传参,传值传参调用拷贝构造函数
		{
			swap(s);
			return *this;
		}

//交换两个string类对象(也是一个成员函数,默认第一个形参是this指针)
void swap(string& s)
		{
            //用全局的swap
            std::swap(s._str, _str);
			std::swap(_size, s._size);
			std::swap(_capacity, s._capacity);
		}

在这里插入图片描述

图 2 图2 2

🥩系列二

1.增容 reserve
void reserve(size_t n)//n:要增到的容量大小
		{
			if (n > _capacity)
			{
				char* tmp = new char[n + 1];//为'\0'多开一个空间
				strcpy(tmp, _str);
				delete[] _str;
				_str = tmp;
				_capacity = n;
			}
		}
2.设置内存大小 resize
void resize(size_t n, char ch = '\0')
		{
			if (n > _capacity)
			{
                //开辟n+1个空间,第n+1个空间的下标是n
				reserve(n);
				memset(_str + _size, ch, n - _size);
				_size = n;
				_str[_size] = '\0';
			}
			else
			{
				_str[n] = '\0';
				_size = n;
			}
		}
3.插入字符 insert
//分析如图3
string& insert(size_t pos, char ch)
		{
            //断言(要引头文件#include<assert.h>)
			assert(pos <= _size);
			if (_size == _capacity)
			{
				//_capacity可能为0
				reserve(_capacity == 0 ? 4 : _capacity * 2);
			}
			size_t end = _size;//_size位置是'\0'
			while (end > pos)
			{
				_str[end + 1] = _str[end];
				end--;
			}
			_str[end] = ch;
			_size++;
			return *this;
		}

在这里插入图片描述

图 3 图3 3

4.插入字符串 insert
string& insert(size_t pos,const char* s)
		{
            //断言
			assert(&& pos <= _size);
			size_t len = strlen(s);
			if (_size == _capacity)
			{
                //会多开辟一个空间
				reserve(_size + strlen(s));
			}
			size_t end = _size;
			while (end>pos)
			{
				_str[end + len] = _str[end];
				end--;
			}
			//限定拷贝字符的长度
			strncpy(_str + pos, s, len);
			_size += len;
			return *this;
		}

在这里插入图片描述

5.尾插字符 push_back
void push_back(char ch)
		{
			insert(_size, ch);
		}
6.尾插字符串 append
void append(const char* s)
		{
			insert(_size, s);
		}

细节🤔:

int main()
{
	my_string::string s1("lllll");
	s1.insert(2, "sss").insert(3, "ddd");
	return 0;
}
7.+=
string& operator+=(char ch)
		{
            //复用
			push_back(ch);
			return *this;
		}

string& operator+=(const char* s)
		{
            //复用
			append(s);
			return *this;
		}
7.字符查找 find
size_t find(char ch)
		{
			for (size_t i = 0; i < _size; i++)
			{
				if (_str[i] == ch)
				{
					return i;
				}
			}
			//npos:无符号整型的最大值,static const size_t npos = -1;
            return npos;
		}
8.字符串查找 find
//从pos位置开始查找
size_t find(const char* s,size_t pos = 0)
		{
			//char* strstr(const char *str1, const char *str2)
            //str2是否是str1的字串
            //如果是则返回第一个字串的起始地址,否则返回nullptr
			const char* tmp = strstr(_str + pos, s);
			if (tmp == nullptr)
			{
				return npos;
			}
			else
			{
                return tmp - _str;//返回下标
			}
		}
9.字符(串)擦除 erase
string& erase(size_t pos = 0, size_t n=npos)
		{
			assert(pos < _size);
			if (n == npos || pos + n >= _size)
			{
				_str[pos] = '\0';
				_size = pos;
			}
			else
			{
                //直接往前覆盖
				strcpy(_str + pos, _str + pos + n);
				/*int end = pos;
				while (end + n < _size)
				{
					_str[end] = _str[end + n];
					end++;
				}*/
				_size -= n;
			}
			return *this;
		}
10.清除 clear
//清除内容,不释放空间
void clear()
		{
			_str[0] = '\0';
			_size = 0;
		}

🥩系列三

1.operator[]
//用于支持修改
char& operator[](size_t pos)
		{
            assert(pos<_size && pos>=0)
			return _str[pos];
		}

//用于支持访问
const char& operator[](size_t pos) const//类成员变量不会被修改,加上const
		{
			assert(pos < _size && pos>=0);
			return _str[pos];
		}
2.c_str
//获取string类里的字符串
const char* c_str() const
		{
			return _str;
		}
3.size
size_t size()
		{
			return _size;
		}

🥩系列四(迭代器)

typedef char* iterator;
typedef const char* const_iterator;

		const_iterator begin() const
		{
			return _str;
		}

		const_iterator end() const
		{
			return _str + _size;
		}

		iterator begin()
		{
			return _str;
		}

		iterator end()
		{
			return _str + _size;
		}

👂三.非成员函数

系列四(关系运算符)

1.operator>
//卷王写法:
bool operator>(const S::string& s1, const S::string& s2)
{
	size_t i = 0;
	while (i < s1.size() && i < s2.size())
	{
		//用[]访问类成员私有变量
		if (s1[i] < s2[i])
		{
			return false;
		}
		else
		{
			i++;
		}
	}
	return s1.size()>i ? true : false;
    //eg: asd  asd  -> false
    //    asd  asdf -> false
    //    asdf asd  -> true -> s1.size()>i
}

//摆王写法:
bool operator>(const S::string& s1, const S::string& s2)
{
    return strcmp(s1.c_str(), s2.c_str()) > 0;
}
2.operator==
//卷王写法:
bool operator==(const S::string& s1, const S::string& s2)
{
	size_t i = 0;
	while (i < s1.size() && i < s2.size())
	{
		if (s1[i] != s2[i])
		{
			return false;
		}
		else
		{
			i++;
		}
	}
	if (i == s1.size() && i == s2.size())
	{
		return true;
	}
	else
	{
		return false;
	}
}

//摆王写法:
bool operator==(const S::string& s1, const S::string& s2)
{
    return strcmp(s1.c_str(),s2.c_str()) == 0;
}

[以下皆可复用]

3.operator>=
bool operator>=(const S::string& s1, const S::string& s2)
{
	return s1 > s2 || s1 == s2;
}

4.operator<
bool operator<(const S::string& s1, const S::string& s2)
{
	return !(s1 >= s2);
}
5.operator<=
bool operator<=(const S::string& s1, const S::string& s2)
{
	return !(s1>s2);
}
6.operator!=
bool operator!=(const S::string& s1, const S::string& s2)
{
	return !(s1 == s2);
}

🥩系列五

1.operator<<
ostream& operator<<(ostream& out, const string& s)
{
	for (size_t i = 0; i < s.size(); ++i)
	{
        //[]支持访问私有
		out << s[i];
	}
    
    //范围for
	/*for (auto c : s)
	{
		out << c;
	}*/
}
2.operator>>
istream& operator>>(istream& in, string& s)
{
	s.clear();
	char ch = in.get();
	while (ch != '\n')
	{
		s += ch;
		ch = in.get();
	}
	return in;
}

🎉完整代码

namespace S
{
	class string
	{
	public:
		typedef char* iterator;
		typedef const char* const_iterator;

		const_iterator begin() const
		{
			return _str;
		}

		const_iterator end() const
		{
			return _str + _size;
		}

		iterator begin()
		{
			return _str;
		}

		iterator end()
		{
			return _str + _size;
		}

		//构造函数
		string(const char* str = "")
			:_str(nullptr), _size(strlen(str)), _capacity(_size)
		{
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}
		//析构函数
		~string()
		{
			//当_str不为nullptr时释放空间
			if (_str)
			{
				delete[] _str;
				_str = nullptr;
				_size = _capacity = 0;
			}
		}
		string(const string& s)
			:_str(nullptr), _size(0), _capacity(0)
		{
			string tmp(s._str);
			swap(tmp);
		}
		//赋值运算符重载
		//现代写法
		void swap(string& s)
		{
            std::swap(s._str, _str);
			std::swap(_size, s._size);
			std::swap(_capacity, s._capacity);
		}
		string& operator=(string s)
		{
			swap(s);
			return *this;
		}

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

		string& insert(size_t pos, char ch)
		{
			assert(pos >= 0 && pos <= _size);
			if (_size == _capacity)
			{
				//_capacity可能为0
				reserve(_capacity == 0 ? 4 : _capacity * 2);
			}
			size_t end = _size;
			while (end > pos)
			{
				_str[end + 1] = _str[end];
				end--;
			}
			_str[end] = ch;
			_size++;
			return *this;
		}

		string& insert(size_t pos, const char* s)
		{
			assert(pos >= 0 && pos <= _size);
			size_t len = strlen(s);
			if (_size == _capacity)
			{
				reserve(_size + strlen(s));
			}
			size_t end = _size;
			while (end>pos)
			{
				_str[end + len] = _str[end];
				end--;
			}
			//限定拷贝字符的长度
			strncpy(_str, s, len);
			_size += len;
			return *this;
		}

		void push_back(char ch)
		{
			insert(_size, ch);
		}

		void append(const char* s)
		{
			insert(_size, s);
		}

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

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

		void resize(size_t n, char ch = '\0')
		{
			if (n > _capacity)
			{
				reserve(n);
				memset(_str + _size, ch, n - _size);
				_size = n;
				_str[_size] = '\0';
			}
			else
			{
				_str[n] = '\0';
				_size = n;
			}
		}

		size_t find(char ch)
		{
			for (size_t i = 0; i < _size; i++)
			{
				if (_str[i] == ch)
				{
					return i;
				}
			}
			return npos;
		}

		//从pos位置开始查找
		size_t find(const char* s,size_t pos = 0)
		{
			//char* strstr(const char *str1, const char *str2)
			char* tmp = strstr(_str + pos, s);
			if (tmp != nullptr)
			{
				return tmp - _str;
			}
			else
			{
				return npos;
			}
		}

		string& erase(size_t pos = 0, size_t n=npos)
		{
			assert(pos >= 0 && pos < _size);
			if (n == npos || pos + n >= _size)
			{
				_str[pos] = '\0';
				_size = pos;
			}
			else
			{
				strcpy(_str + pos, _str + pos + n);
				_size -= n;
			}
			return *this;
		}

		//用于支持修改
		char& operator[](size_t pos)
		{
			assert(pos < _size && pos >= 0);
			return _str[pos];
		}

		//用于支持访问
		const char& operator[](size_t pos) const//类成员变量不会被修改,加上const
		{
			assert(pos < _size && pos >= 0);
			return _str[pos];
		}
		char* c_str() const 
		{
			return _str;
		}

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

		size_t size() const
		{
			return _size;
		}

	private:
		char* _str;
		int _size;
		int _capacity;
	public:
		static const size_t npos = -1;
	};
}

bool operator>(const S::string& s1, const S::string& s2)
{
	size_t i = 0;
	while (i < s1.size() && i < s2.size())
	{
		//用[]访问类成员私有变量
		if (s1[i] < s2[i])
		{
			return false;
		}
		else
		{
			i++;
		}
	}
	return s1.size()>i ? true : false;
}

bool operator==(const S::string& s1, const S::string& s2)
{
	size_t i = 0;
	while (i < s1.size() && i < s2.size())
	{
		if (s1[i] != s2[i])
		{
			return false;
		}
		else
		{
			i++;
		}
	}
	if (i == s1.size() && i == s2.size())
	{
		return true;
	}
	else
	{
		return false;
	}
}

bool operator>=(const S::string& s1, const S::string& s2)
{
	return s1 > s2 || s1 == s2;
}

bool operator<(const S::string& s1, const S::string& s2)
{
	return !(s1 >= s2);
}

bool operator<=(const S::string& s1, const S::string& s2)
{
	return !(s1>s2);
}

bool operator!=(const S::string& s1, const S::string& s2)
{
	return !(s1 == s2);
}

ostream& operator<<(ostream& out, const string& s)
{
	for (size_t i = 0; i < s.size(); ++i)
	{
		//[]支持访问私有
		out << s[i];
	}
}

istream& operator>>(istream& in, string& s)
{
	s.clear();
	char ch = in.get();
	while (ch != '\n')
	{
		s += ch;
		ch = in.get();
	}
	return in;
}

🎶练习

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

namespace S
{
	class string
	{
	public:
		typedef char* iterator;
		typedef const char* const_iterator;

		const_iterator begin() const

		const_iterator end() const

		iterator begin()
		
		iterator end()
	
		string(const char* str = "")
            
		~string()

		string& operator=(string s)
	
		void reserve(size_t n)

		string& insert(size_t pos, char ch)

		string& insert(size_t pos, const char* s)
	
		void push_back(char ch)
		
		void append(const char* s)
		
		string& operator+=(char ch)

		string& operator+=(const char* s)

		void resize(size_t n, char ch = '\0')

		size_t find(char ch)

		size_t find(const char* s,size_t pos = 0)

		string& erase(size_t pos = 0, size_t n=npos)

		char& operator[](size_t pos)

		const char& operator[](size_t pos) const
		
		char* c_str() const 

		void clear()
            
		size_t size() const
	private:
		char* _str;
		int _size;
		int _capacity;
	public:
		static const size_t npos = -1;
	};
}

bool operator>(const S::string& s1, const S::string& s2)

bool operator==(const S::string& s1, const S::string& s2)
	
bool operator>=(const S::string& s1, const S::string& s2)

bool operator<(const S::string& s1, const S::string& s2)

bool operator<=(const S::string& s1, const S::string& s2)

bool operator!=(const S::string& s1, const S::string& s2)

ostream& operator<<(ostream& out, const string& s)

istream& operator>>(istream& in, string& s)

	string& operator+=(const char* s)

	void resize(size_t n, char ch = '\0')

	size_t find(char ch)

	size_t find(const char* s,size_t pos = 0)

	string& erase(size_t pos = 0, size_t n=npos)

	char& operator[](size_t pos)

	const char& operator[](size_t pos) const
	
	char* c_str() const 

	void clear()
        
	size_t size() const
private:
	char* _str;
	int _size;
	int _capacity;
public:
	static const size_t npos = -1;
};

}

bool operator>(const S::string& s1, const S::string& s2)

bool operator==(const S::string& s1, const S::string& s2)

bool operator>=(const S::string& s1, const S::string& s2)

bool operator<(const S::string& s1, const S::string& s2)

bool operator<=(const S::string& s1, const S::string& s2)

bool operator!=(const S::string& s1, const S::string& s2)

ostream& operator<<(ostream& out, const string& s)

istream& operator>>(istream& in, string& s)


> 最后,笔者想说的是,string的成员函数还有很多,这里模拟实现的都是string中较为常用的,其他的函数读者有兴趣的话可以自己下去模拟实现一下,当然也可与笔者一起交流学习!😁🤪😆
举报

相关推荐

string模拟实现

string模拟实现:

string【2】模拟实现string类

C++string的模拟实现

【C++】string的模拟实现

c++ string模拟实现

9.string模拟实现

0 条评论