深剖string内部结构 手撕string

个人主页:小则又沐风

个人专栏:<数据结构>

<竞赛专栏>

<C语言>
<C++>

目录

前言:

准备工作:

​编辑构造函数:

析构函数

迭代器

容量接口

遍历接口实现

增删查改

[void push_back(char c);](#void push_back(char c);)

[string& operator+=(char c);](#string& operator+=(char c);)

[void append(const char* str);](#void append(const char* str);)

[string& operator+=(const char* str);](#string& operator+=(const char* str);)

[void clear();](#void clear();)

[void swap(string& s);](#void swap(string& s);)

[const char* c_str()const;](#const char* c_str()const;)

[size_t find(char c, size_t pos = 0) const;](#size_t find(char c, size_t pos = 0) const;)

[size_t find(const char* s, size_t pos = 0) const;](#size_t find(const char* s, size_t pos = 0) const;)

[void insert(size_t pos, char c);](#void insert(size_t pos, char c);)

[void insert(size_t pos, const char* str);](#void insert(size_t pos, const char* str);)

[size_t erase(size_t pos, size_t len);](#size_t erase(size_t pos, size_t len);)

输入流重载

输出流重载

比较运算符的重载

头文件:

cpp文件


前言:

在前面我们知道了在标准库中的string的各种接口和使用的方法,今天我们就来接触一下底层,

来模拟实现一下这个string的类

准备工作:

我们把创建出一个头文件---包含了各种的声明

两个cpp文件----一个就是我们string的各种的实现 另一个就是我们的测试的地方也是我们的main函数所在的地方.这样会让我们的代码更好的管理

构造函数:

在之前的调试的过程中我们知道了在string中应该含有的成员变量是一个指向字符串的指针,一个代表有效的字符个数的size和空间大小的capacity;

cpp 复制代码
#pragma once
#include<iostream>
using namespace std;
namespace jzx
{
	class string
	{
	private:
		char* _str;
		size_t size;
		size_t capacity;
	};
}

那么下面我们就是来写一个构造函数

就来实现一下几个非常常用的几个首先就是这个

string(const char* str = "");

我们传入一个常量字符串来构造出一个string

cpp 复制代码
jzx::string::string(const char* str)
{
	size_t len = strlen(str);
	_str = new char[len + 1];
	strcpy(_str, str);
	_size = len;
	_capacity = _size;
}

这就是这个构造函数,我们来测试一下

cpp 复制代码
#include"mystring.h"
void text1()
{
	jzx::string s("hello");
}
int main()
{
	text1();
	return 0;
}

看起来是可以的

下面就是这个拷贝构造函数

string(const string& s);

cpp 复制代码
zx::string::string(const string& s)
{
	_size = s._size;
	_capacity = s._capacity;
	_str = new char[s._capacity+1];
	strcpy(_str, s._str);
}

下面就是赋值的重载函数

string& operator=(const string &s);

cpp 复制代码
string& operator=(const string& s)
{
	if (this != &s)
	{
		delete[]_str;
		_size = s._size;
		_capacity = s._capacity;
		_str = new char[s._capacity + 1];
		strcpy(_str, s._str);
	}
	return *this;
}
cpp 复制代码
void text3()
{
	jzx::string s("hello");
	jzx::string s1;
	s1 = s;
}

测试代码

这就是最常用的两个构造函数和赋值的重载的函数

下面就是析构函数

析构函数

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

下面就是迭代器的封装:

迭代器

string的迭代器只不过就是一个char*的指针

typedef char* iterator;

typedef const char* const_iterator;

这就是我们的迭代器的真面目

下面我们来实现一下这个begin和end

cpp 复制代码
iterator begin()
{
	return _str;
}
const_iterator begin()const
{
	return  _str;
}
iterator end()
{
	return _str + _size;
}
const_iterator end()const
{
	return _str + _size;
}

下面实现有关于string的容量的接口

容量接口

size_t size()const

size_t capacity()const

bool empty()const

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

void reserve(size_t n);

cpp 复制代码
size_t size()const
{
	return _size;
}

size_t capacity()const
{
	return _capacity;
}
bool empty()const
{
	return _size == 0;
}
cpp 复制代码
void jzx::string:: resize(size_t n, char c)
{
	if (n <= _size)
	{
		_str[n] = '\0';
		_size = n;
		return;
	}
	else
	{
		if (_capacity < n)
		{
			reserve(n);
		}
		for (size_t i = _size; i < n; i++)
		{
			_str[i] = c;
		}
		_size = n;
		_str[_size] = '\0';
	}
}
void jzx::string::reserve(size_t n)
{
	if (n <= _capacity)
	{
		return;
	}
	else
	{
		char* temp = new char[n + 1];
		strcpy(temp, _str);
		delete[]_str;
		_str = temp;
		_capacity =n;
	}
}

下面就是实现这个[]的接口

遍历接口实现

char& operator[](size_t index);

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

cpp 复制代码
char& operator[](size_t index)
{
	assert(index < _size);
	return _str[index];
}
const char& operator[](size_t index)const
{
	assert(index < _size);
	return _str[index];
}

下面就是实现增删查改的操作

增删查改


void push_back(char c);

string& operator+=(char c);

void append(const char* str);

string& operator+=(const char* str);

void clear();

void swap(string& s);

const char* c_str()const;

void push_back(char c);

cpp 复制代码
void jzx::string::push_back(char c)
{
	if (_size == _capacity)
	{
		size_t newcapacity;
		if (_capacity == 0)
		{
			newcapacity = 4;
		}
		else
		{
			newcapacity = 2 * _capacity;
		}
		reserve(newcapacity);
	}
	_str[_size] = c;
	_str[_size + 1] = '\0';
	_size++;
}

string& operator+=(char c);

cpp 复制代码
string& operator+=(char c)
{
    push_back(c);
    return *this;
}

void append(const char* str);

cpp 复制代码
void jzx::string::append(const char* str)
{
	size_t len = _size + strlen(str);
	if (len > _capacity)
	{
		reserve(len);
	}
	strcpy(_str + _size, str);
	_size = len;
}

string& operator+=(const char* str);

cpp 复制代码
string& operator+=(const char* str)
{
	append(str);
	return *this;
}

void clear();

cpp 复制代码
void jzx::string::clear()
{
	_size = 0;
	_str[_size] = '\0';
}

void swap(string& s);

cpp 复制代码
void jzx::string::swap(string& s)
{
	std::swap(_str, s._str);
	std::swap(_size, s._size);
	std::swap(_capacity, s._capacity);
}

const char* c_str()const;

cpp 复制代码
const char* jzx::string:: c_str()const
{
	return _str;
}

下面就是是实现一下insert这类的接口了

size_t find(char c, size_t pos = 0) const;

这个函数就是实现在字符串中找到第一个出现字符c的pos的位置

cpp 复制代码
size_t jzx::string::find(char c, size_t pos) const
{
	for (size_t i = pos; i < _size; i++)
	{
		if (_str[i] == c)
		{
			return i;
		}
    }
	return npos;
}

在这里我的代码写的是如果没有找到就返回npos就是我定义的-1;

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

这个就是把上面的字符变成了字符串

cpp 复制代码
size_t jzx::string::find(const char* s, size_t pos ) const
{
	char* key = strstr(_str+pos, s);
	if (key == nullptr)
	{
		return npos;
	}
	else
	{
		return key - _str;
	}
}

void insert(size_t pos, char c);

先检查是否需要扩容然后挪动数据放置数据

cpp 复制代码
void jzx::string::insert(size_t pos, char c)
{
	assert(pos <= _size);
	if (_size == _capacity)
	{
		size_t newcapacity;
		if (_capacity == 0)
		{
			newcapacity = 4;
		}
		else
		{
			newcapacity = 2 * _capacity;
		}
		reserve(newcapacity);
	}
    size_t i = _size+1;
	while (i > pos)
	{
		_str[i]=_str[i-1];
		i--;
	}
	_str[pos] = c;
	_size++;
}

下面就是在字符串中插入字符串了

void insert(size_t pos, const char* str);

cpp 复制代码
void jzx::string::insert(size_t pos, const char* str)
{
	size_t s = strlen(str);
	int len = _size + s;
	if (len > _capacity)
	{
		size_t newcapacity;
		if (len > _capacity * 2)
		{
			newcapacity = len;
		}
		else
		{
			newcapacity = _capacity * 2;
		}
		reserve(newcapacity);
	}
	size_t i = _size + s;
	while (i > pos+s-1)
	{
		_str[i] = _str[i - s];
		i--;
	}
	strncpy(_str + pos, str,s);
	_size += s;
}

size_t erase(size_t pos, size_t len);

cpp 复制代码
size_t jzx::string::erase(size_t pos, size_t len)
{
	assert(pos <= _size);
	if (len >= _size - pos)
	{
		_str[pos] = '\0';
		_size = pos;
	}
	else
	{
		for (size_t i = pos+len; i <= _size; i++)
		{
			_str[i - len] = _str[i];
		}
		_size -= len;
	}
	return pos;
}

下面就是重载一下输入和输出流

输入流重载

friend istream& operator>>(istream& _cin,jzx::string& s);

cpp 复制代码
 istream& jzx::operator>>(istream& _cin, jzx::string& s)
{
	 s.clear();
	 s.reserve(156);
	 char ch;
	 int i = 0;
	 while (_cin.get(ch))
	 {
		 if (ch == ' ' || ch == '\n')
		 {
			 break;
		 }
		 s += ch;
		 i++;
	 }
	/* s += '\0';*/
	 return _cin;
}

输出流重载

cpp 复制代码
ostream& jzx::operator<<(ostream& _cout,const jzx:: string& s)
{
 for (auto V : s)
 {
	 _cout << V;
 }
 return _cout;
}

下面就是比较运算符的重载

比较运算符的重载

bool operator<(const string& s);

bool operator<=(const string& s);

bool operator>(const string& s);

bool operator>=(const string& s);

bool operator==(const string& s);

bool operator!=(const string& s);

cpp 复制代码
bool jzx::string::operator<(const string& s)
{
 return strcmp(c_str(), s.c_str()) < 0;
}

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

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

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

bool jzx::string::operator==(const string& s)
{
 return strcmp(c_str(), s.c_str()) == 0;
}

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

以上就是我们模拟实现的string的常用的接口和函数

下面分别是头文件和cpp文件

头文件:

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<iostream>
#include<assert.h>
#include<cstring>
using namespace std;
namespace jzx
{
	class string
	{
	public:
		const size_t npos = -1;



	public:

		friend ostream& operator<<(ostream& _cout, const jzx::string& s);
		friend istream&  operator>>(istream& _cin, jzx::string& s);
	public:
		typedef char* iterator;
		typedef const char* const_iterator;
	public:
		string(const char* str = "");
		string(const string& s);
		string& operator=(const string& s)
		{
			if (this != &s)
			{
				delete[]_str;
				_size = s._size;
				_capacity = s._capacity;
				_str = new char[s._capacity + 1];
				strcpy(_str, s._str);
			}
			return *this;
		}
		/*bool operator==(const string& s) const
		{
			return strcmp(_str, s._str) == 0;
		}*/
		~string()
		{
			delete[]_str;
			_str = nullptr;
			_capacity = _size = 0;
		}



	public:
		iterator begin()
		{
			return _str;
		}
		const_iterator begin()const
		{
			return  _str;
		}
		iterator end()
		{
			return _str + _size;
		}
		const_iterator end()const
		{
			return _str + _size;
		}



	public:
		size_t size()const
		{
			return _size;
		}

		size_t capacity()const
		{
			return _capacity;
		}
		bool empty()const
		{
			return _size == 0;
		}
		void resize(size_t n, char c = '\0');
		void reserve(size_t n);


	public:
		char& operator[](size_t index)
		{
			assert(index < _size);
			return _str[index];
		}
		const char& operator[](size_t index)const
		{
			assert(index < _size);
			return _str[index];
		}


	public:
		void push_back(char c);

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

		void append(const char* str);

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

		void swap(string& s);

		const char* c_str()const;




	public:
		// 返回c在string中第一次出现的位置

		size_t find(char c, size_t pos = 0) const;

		// 返回子串s在string中第一次出现的位置

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

		// 在pos位置上插入字符c/字符串str,并返回该字符的位置

		void insert(size_t pos, char c);

		void insert(size_t pos, const char* str);



		// 删除pos位置上的元素,并返回该元素的下一个位置

		size_t erase(size_t pos, size_t len);


		public:
			//relational operators

			bool operator<(const string& s); 

			bool operator<=(const string& s);

			bool operator>(const string& s); 

			bool operator>=(const string& s); 

			bool operator==(const string& s); 

			bool operator!=(const string& s); 
	private:
		char* _str;
		size_t _size;
		size_t _capacity;
	};
}
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<iostream>
#include<assert.h>
#include<cstring>
using namespace std;
namespace jzx
{
	class string
	{
	public:
		const size_t npos = -1;



	public:

		friend ostream& operator<<(ostream& _cout, const jzx::string& s);
		friend istream&  operator>>(istream& _cin, jzx::string& s);
	public:
		typedef char* iterator;
		typedef const char* const_iterator;
	public:
		string(const char* str = "");
		string(const string& s);
		string& operator=(const string& s)
		{
			if (this != &s)
			{
				delete[]_str;
				_size = s._size;
				_capacity = s._capacity;
				_str = new char[s._capacity + 1];
				strcpy(_str, s._str);
			}
			return *this;
		}
		/*bool operator==(const string& s) const
		{
			return strcmp(_str, s._str) == 0;
		}*/
		~string()
		{
			delete[]_str;
			_str = nullptr;
			_capacity = _size = 0;
		}



	public:
		iterator begin()
		{
			return _str;
		}
		const_iterator begin()const
		{
			return  _str;
		}
		iterator end()
		{
			return _str + _size;
		}
		const_iterator end()const
		{
			return _str + _size;
		}



	public:
		size_t size()const
		{
			return _size;
		}

		size_t capacity()const
		{
			return _capacity;
		}
		bool empty()const
		{
			return _size == 0;
		}
		void resize(size_t n, char c = '\0');
		void reserve(size_t n);


	public:
		char& operator[](size_t index)
		{
			assert(index < _size);
			return _str[index];
		}
		const char& operator[](size_t index)const
		{
			assert(index < _size);
			return _str[index];
		}


	public:
		void push_back(char c);

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

		void append(const char* str);

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

		void swap(string& s);

		const char* c_str()const;




	public:
		// 返回c在string中第一次出现的位置

		size_t find(char c, size_t pos = 0) const;

		// 返回子串s在string中第一次出现的位置

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

		// 在pos位置上插入字符c/字符串str,并返回该字符的位置

		void insert(size_t pos, char c);

		void insert(size_t pos, const char* str);



		// 删除pos位置上的元素,并返回该元素的下一个位置

		size_t erase(size_t pos, size_t len);


		public:
			//relational operators

			bool operator<(const string& s); 

			bool operator<=(const string& s);

			bool operator>(const string& s); 

			bool operator>=(const string& s); 

			bool operator==(const string& s); 

			bool operator!=(const string& s); 
	private:
		char* _str;
		size_t _size;
		size_t _capacity;
	};
}

cpp文件

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include "mystring.h"
jzx::string::string(const char* str)
{
	size_t len = strlen(str);
	_str = new char[len + 1];
	strcpy(_str, str);
	_size = len;
	_capacity = _size;
}
jzx::string::string(const string& s)
{
	_size = s._size;
	_capacity = s._capacity;
	_str = new char[s._capacity+1];
	strcpy(_str, s._str);
}
void jzx::string:: resize(size_t n, char c)
{
	if (n <= _size)
	{
		_str[n] = '\0';
		_size = n;
		return;
	}
	else
	{
		if (_capacity < n)
		{
			reserve(n);
		}
		for (size_t i = _size; i < n; i++)
		{
			_str[i] = c;
		}
		_size = n;
		_str[_size] = '\0';
	}
}
void jzx::string::reserve(size_t n)
{
	if (n <= _capacity)
	{
		return;
	}
	else
	{
		char* temp = new char[n + 1];
		strcpy(temp, _str);
		delete[]_str;
		_str = temp;
		_capacity =n;
	}
}
void jzx::string::push_back(char c)
{
	if (_size == _capacity)
	{
		size_t newcapacity;
		if (_capacity == 0)
		{
			newcapacity = 4;
		}
		else
		{
			newcapacity = 2 * _capacity;
		}
		reserve(newcapacity);
	}
	_str[_size] = c;
	_str[_size + 1] = '\0';
	_size++;
}
void jzx::string::append(const char* str)
{
	size_t len = _size + strlen(str);
	if (len > _capacity)
	{
		reserve(len);
	}
	strcpy(_str + _size, str);
	_size = len;
}
void jzx::string::clear()
{
	_size = 0;
	_str[_size] = '\0';
}
void jzx::string::swap(string& s)
{
	std::swap(_str, s._str);
	std::swap(_size, s._size);
	std::swap(_capacity, s._capacity);
}
const char* jzx::string:: c_str()const
{
	return _str;
}

size_t jzx::string::find(char c, size_t pos) const
{
	for (size_t i = pos; i < _size; i++)
	{
		if (_str[i] == c)
		{
			return i;
		}
    }
	return npos;
}
size_t jzx::string::find(const char* s, size_t pos ) const
{
	char* key = strstr(_str+pos, s);
	if (key == nullptr)
	{
		return npos;
	}
	else
	{
		return key - _str;
	}
}

void jzx::string::insert(size_t pos, char c)
{
	assert(pos <= _size);
	if (_size == _capacity)
	{
		size_t newcapacity;
		if (_capacity == 0)
		{
			newcapacity = 4;
		}
		else
		{
			newcapacity = 2 * _capacity;
		}
		reserve(newcapacity);
	}
    size_t i = _size+1;
	while (i > pos)
	{
		_str[i]=_str[i-1];
		i--;
	}
	_str[pos] = c;
	_size++;
}

void jzx::string::insert(size_t pos, const char* str)
{
	size_t s = strlen(str);
	int len = _size + s;
	if (len > _capacity)
	{
		size_t newcapacity;
		if (len > _capacity * 2)
		{
			newcapacity = len;
		}
		else
		{
			newcapacity = _capacity * 2;
		}
		reserve(newcapacity);
	}
	size_t i = _size + s;
	while (i > pos+s-1)
	{
		_str[i] = _str[i - s];
		i--;
	}
	strncpy(_str + pos, str,s);
	_size += s;
}
size_t jzx::string::erase(size_t pos, size_t len)
{
	assert(pos <= _size);
	if (len >= _size - pos)
	{
		_str[pos] = '\0';
		_size = pos;
	}
	else
	{
		for (size_t i = pos+len; i <= _size; i++)
		{
			_str[i - len] = _str[i];
		}
		_size -= len;
	}
	return pos;
}
 istream& jzx::operator>>(istream& _cin, jzx::string& s)
{
	 s.clear();
	 s.reserve(156);
	 char ch;
	 int i = 0;
	 while (_cin.get(ch))
	 {
		 if (ch == ' ' || ch == '\n')
		 {
			 break;
		 }
		 s += ch;
		 i++;
	 }
	/* s += '\0';*/
	 return _cin;
}
 ostream& jzx::operator<<(ostream& _cout,const jzx:: string& s)
 {
	 for (auto V : s)
	 {
		 _cout << V;
	 }
	 return _cout;
 }

 bool jzx::string::operator<(const string& s)
 {
	 return strcmp(c_str(), s.c_str()) < 0;
 }

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

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

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

 bool jzx::string::operator==(const string& s)
 {
	 return strcmp(c_str(), s.c_str()) == 0;
 }

 bool jzx::string::operator!=(const string& s)
 {
	 return !((*this) == s);
 }
相关推荐
m0_377618231 小时前
SQL如何解决GROUP BY导致查询变慢_利用覆盖索引进行优化
jvm·数据库·python
Garcia Shan1 小时前
【SQL Server】SQL Server中的DENSE_RANK()
数据库·sql
qq_334563551 小时前
如何提高SQL存储过程可维护性_解耦复杂业务逻辑
jvm·数据库·python
2401_832635581 小时前
Spring Data MongoDB 最佳实践:如何构建高效数据访问层
java·mongodb·spring
2301_777599371 小时前
Golang map底层实现原理_Golang map哈希表原理教程【收藏】
jvm·数据库·python
亚马逊云开发者1 小时前
Java 8升级Java 17实战:用AWS Transform Custom自动化迁移Spring Boot项目完整教程
java·自动化·aws
不恋水的雨1 小时前
html中补齐table表格合并导致每行td数量不一致的情况
前端·html
会编程的土豆1 小时前
常用算法里的细节
数据结构·c++·算法·图论
2301_813599551 小时前
Go语言怎么用AWS S3_Go语言S3对象存储教程【总结】
jvm·数据库·python