C/C++ 入门(7)string类(STL)

个人主页:仍有未知等待探索-CSDN博客

专题分栏:C++

请多多指教!

目录

一、标准库中的string

1、了解

2、string类常用接口说明

1、常见的构造函数

[2、容量操作 ​编辑](#2、容量操作 编辑)

3、访问及遍历操作

4、修改操作

5、非成员函数

二、string类实现

1、string类的大体框架

2、构造和析构函数

3、迭代器

4、成员函数

5、非成员函数

三、问题

1、深拷贝和浅拷贝问题

2、strcpy,memcpy

四、总代码


一、标准库中的string

1、了解

1、string是表示字符串的字符串类

2、该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。

2、string类常用接口说明

下面的函数都可以去下面的网址进行查文档,来看函数的功能。(接下来我会实现这个string类)

string - C++ Reference

1、常见的构造函数

|--------------------------|----------------------|
| 函数名称 | 功能说明 |
| string() | 构造空的string类,即空字符串 |
| string(const char*s) | 用c_str()来构造string类对象 |
| string(size_t n, char c) | string类对象中包含n个字符c |
| string(const string& s) | 拷贝构造函数 |
[string类对象的常见构造]

2、容量操作

3、访问及遍历操作

4、修改操作

5、非成员函数

二、string类实现

实现string类能让我们更好的明白模板的使用,函数重载等等。

1、string类的大体框架

cpp 复制代码
#include <iostream>
#include <cstring>
#include <assert.h>
using namespace std;

class string
{
public:

private:
	char* _str; // string存的字符串
	size_t _size; // string中字符串的长度 
	size_t _capacity; // string的容量
};

2、构造和析构函数

cpp 复制代码
string()
	:_str(nullptr)
	,_size(0)
	,_capacity(0)
{}
string(const char* str)
	:_size(strlen(str))
	,_capacity(_size)
{
	_str = new char[_capacity + 1];
	strcpy(_str, str);
}
string(const string& str)
	:_str(new char[str._capacity + 1])
	,_size(str._size)
	,_capacity(str._capacity)
{
	strcpy(_str, str._str);
}
~string()
{
	delete[] _str;
	_str = nullptr;
	_size = 0;
	_capacity = 0;
}

3、迭代器

cpp 复制代码
typedef char* iterator;
iterator begin()
{
	return _str;
}
iterator end()
{
	return _str + _size;
}

4、成员函数

cpp 复制代码
string& operator=(const string& str)
{
	char* tmp = new char[str._capacity + 1];
	strcpy(tmp, str._str);
	delete[] _str;
	_str = tmp;
	_size = str._size;
	_capacity = str._capacity;
	return *this;
}
void reserve(int x)
{
	if (_capacity < x)
	{
		char* tmp = new char[x + 1];
		strcpy(tmp, _str);
		delete[] _str;
		_str = tmp;
		_capacity = x;
	}
}
void swap(string& str)
{
	std::swap(_str, str._str);
	std::swap(_size, str._size);
	std::swap(_capacity, str._capacity);
}
const char* c_str() const
{
	return _str;
}
void clear()
{
	_str[0] = '\0';
	_size = 0;
}
void insert(int index, const string& str)
{
	int len = str._size;
	assert(index >= 0 && index < _size);
	if (_size + len >= _capacity)
	{
		reserve(_capacity + len);
	}
	for (int i = _size - 1; i >= index; i -- )
	{
		_str[i + len] = _str[i];
	}
	for (int j = 0, i = index; j < str._size; j ++ ,i ++ )
	{
		_str[i] = str._str[j];
	}
	_size += len;
}
void insert(int index, char ch)
{
	assert(index >= 0 && index < _size);
	if (_size + 1 >= _capacity)
	{
		reserve(2 * _capacity);
		_capacity *= 2;
	}
	for (int i = _size - 1; i >= index; i -- )
	{
		_str[i + 1] = _str[i];
	}
	_str[index] = ch;
	_size ++ ;
	
}
void append(const string& str)
{
	int len = str._size;
	if (len + _size > _capacity)
	{
		reserve(len + _size);
		_capacity = len * _size;
	}
	int end = _size;
	for (int i = 0; i < str._size; i ++ ,end ++ )
	{
		_str[end] = str._str[i];
	}
	_size += len;
}
string& operator+=(const string& str)
{
	append(str);
	return *this;
}
void push_back(const char ch)
{
	if (_size + 1 >= _capacity)
	{
		reserve(2 * _capacity);
	}
	_capacity *= 2;
	_str[_size] = ch;
	_size ++ ;
}
int size() const
{
	return _size;
}
int capacity() const
{
	return _capacity;
}
bool empty() const
{
	return _size == 0;
}
void resize(int n, char ch = '\0')
{
	if (n < _size)
	{
		for (int i = n; i < _size; i ++ )
		{
			_str[i] = '\0';
		}
	}
	else if (n + 1 < _capacity)
	{
		for (int i = _size; i < n; i ++ )
		{
			_str[i] = ch;
		}
	}
	else
	{
		reserve(n);
	}
}
char& operator[](size_t index)
{
	assert(index < _size);
	return _str[index];
}
const char& operator[](size_t index)const
{
	assert(index < _size);
	return _str[index];
}
bool operator==(const string& str)
{
	int ret = strcmp(_str, str.c_str());
	return ret == 0;
}
bool operator!=(const string& str)
{
	return !(*this == str);
}
bool operator>(const string& str)
{
	int ret = strcmp(_str, str.c_str());
	return ret > 0;
}
bool operator<(const string& str)
{
	int ret = strcmp(_str, str.c_str());
	return ret < 0;
}
bool operator<=(const string& str)
{
	return *this < str || *this == str;
}
bool operator>=(const string& str)
{
	return *this > str || *this == str;
}
int find (char c, size_t pos = 0) const
{
	assert(pos < _size);
	for (int i = pos; i < _size; i ++ )
	{
		if (_str[i] == c) return i;
	}
	return npos;
}
int find (const char* s, size_t pos = 0) const
{
	char* p = strstr(_str + pos, s);
	if (p != nullptr)
	{
		return p - _str;
	}
	return npos;
}
string& erase (size_t pos = 0, size_t len = npos)
{
	assert(pos < _size);
	if (len == npos || len >= _size - pos)
	{
		_str[pos] = '\0';
		_size = pos;
	}
	else
	{
		int i = 0;
		for (i = pos + len; i < _size; i ++ )
		{
			_str[i - len] = _str[i];
		}
		_str[i] = '\0';
		_size -= len;
	}
	return *this;
}

5、非成员函数

cpp 复制代码
    ostream& operator<<(ostream& out, const string& str)
	{
		int len = str._size;
		for (int i = 0; i < len; i ++ )
		{
			out << str._str[i];
		}
		return out;
	}
    istream& operator>>(istream& in, string& str)
	{
		str.clear();
		char ch = in.get();
		char buff[128];
		int i = 0;
		while (ch != ' ' && ch != '\n')
		{
			buff[i ++ ] = ch;
			if (i == 127)
			{
				buff[i] = '\0';
				str += buff;
				i = 0;
			}
			ch = in.get();
		}

		if (i != 0)
		{
			buff[i] = '\0';
			str += buff;
		}
		return in;
	}
}

三、问题

1、深拷贝和浅拷贝问题

**浅拷贝:**也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以当继续对资源进项操作时,就会发生发生了访问违规。


**深拷贝:**每个对象都有一份独立的资源,不要和其他对象共享。如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。一般情况都是按照深拷贝方式提供。

2、strcpy,memcpy

通过下面的例子也能清晰的看出来,这两个拷贝函数都是浅拷贝。所以在用的时候需要小心谨慎。

四、总代码

cpp 复制代码
#include <iostream>
#include <cstring>
#include <assert.h>
using namespace std;

namespace my
{
	class string
	{
	public:
		string()
			:_str(nullptr)
			,_size(0)
			,_capacity(0)
		{}
		string(const char* str)
			:_size(strlen(str))
			,_capacity(_size)
		{
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}
		string(const string& str)
			:_str(new char[str._capacity + 1])
			,_size(str._size)
			,_capacity(str._capacity)
		{
			strcpy(_str, str._str);
		}
		~string()
		{
			delete[] _str;
			_str = nullptr;
			_size = 0;
			_capacity = 0;
		}
		typedef char* iterator;
		iterator begin()
		{
			return _str;
		}
		iterator end()
		{
			return _str + _size;
		}

		string& operator=(const string& str)
		{
			char* tmp = new char[str._capacity + 1];
			strcpy(tmp, str._str);
			delete[] _str;
			_str = tmp;
			_size = str._size;
			_capacity = str._capacity;
			return *this;
		}
		void reserve(int x)
		{
			if (_capacity < x)
			{
				char* tmp = new char[x + 1];
				strcpy(tmp, _str);
				delete[] _str;
				_str = tmp;
				_capacity = x;
			}
		}
		void swap(string& str)
		{
			std::swap(_str, str._str);
			std::swap(_size, str._size);
			std::swap(_capacity, str._capacity);
		}
		const char* c_str() const
		{
			return _str;
		}
		void clear()
		{

			_str[0] = '\0';
			_size = 0;
			_capacity = 0;
		}
		void insert(int index, const string& str)
		{
			int len = str._size;
			assert(index >= 0 && index < _size);
			if (_size + len >= _capacity)
			{
				reserve(_capacity + len);
			}
			for (int i = _size - 1; i >= index; i -- )
			{
				_str[i + len] = _str[i];
			}
			for (int j = 0, i = index; j < str._size; j ++ ,i ++ )
			{
				_str[i] = str._str[j];
			}
			_size += len;
		}
		void insert(int index, char ch)
		{
			assert(index >= 0 && index < _size);
			if (_size + 1 >= _capacity)
			{
				reserve(2 * _capacity);
				_capacity *= 2;
			}
			for (int i = _size - 1; i >= index; i -- )
			{
				_str[i + 1] = _str[i];
			}
			_str[index] = ch;
			_size ++ ;

		}
		void append(const string& str)
		{
			int len = str._size;
			if (len + _size > _capacity)
			{
				reserve(len + _size);
				_capacity = len * _size;
			}
			int end = _size;
			for (int i = 0; i < str._size; i ++ ,end ++ )
			{
				_str[end] = str._str[i];
			}
			_size += len;
		}
		string& operator+=(const string& str)
		{
			append(str);
			return *this;
		}
		void push_back(const char ch)
		{
			if (_size + 1 >= _capacity)
			{
				reserve(2 * _capacity);
			}
			_capacity *= 2;
			_str[_size] = ch;
			_size ++ ;
		}
		int size() const
		{
			return _size;
		}
		int capacity() const
		{
			return _capacity;
		}
		bool empty() const
		{
			return _size == 0;
		}
		void resize(int n, char ch = '\0')
		{
			if (n < _size)
			{
				for (int i = n; i < _size; i ++ )
				{
					_str[i] = '\0';
				}
			}
			else if (n + 1 < _capacity)
			{
				for (int i = _size; i < n; i ++ )
				{
					_str[i] = ch;
				}
			}
			else
			{
				reserve(n);
			}
		}
		char& operator[](size_t index)
		{
			assert(index < _size);
			return _str[index];
		}
		const char& operator[](size_t index)const
		{
			assert(index < _size);
			return _str[index];
		}
		bool operator==(const string& str)
		{
			int ret = strcmp(_str, str.c_str());
			return ret == 0;
		}
		bool operator!=(const string& str)
		{
			return !(*this == str);
		}
		bool operator>(const string& str)
		{
			int ret = strcmp(_str, str.c_str());
			return ret > 0;
		}
		bool operator<(const string& str)
		{
			int ret = strcmp(_str, str.c_str());
			return ret < 0;
		}
		bool operator<=(const string& str)
		{
			return *this < str || *this == str;
		}
		bool operator>=(const string& str)
		{
			return *this > str || *this == str;
		}
		int find (char c, size_t pos = 0) const
		{
			assert(pos < _size);
			for (int i = pos; i < _size; i ++ )
			{
				if (_str[i] == c) return i;
			}
			return npos;
		}
		int find (const char* s, size_t pos = 0) const
		{
			char* p = strstr(_str + pos, s);
			if (p != nullptr)
			{
				return p - _str;
			}
			return npos;
		}
		string& erase (size_t pos = 0, size_t len = npos)
		{
			assert(pos < _size);
			if (len == npos || len >= _size - pos)
			{
				_str[pos] = '\0';
				_size = pos;
			}
			else
			{
				int i = 0;
				for (i = pos + len; i < _size; i ++ )
				{
					_str[i - len] = _str[i];
				}
				_str[i] = '\0';
				_size -= len;
			}
			return *this;
		}
		friend ostream& operator<<(ostream& out, const string& str);
		friend istream& operator>>(istream& in, string& str);
	private:
		char* _str; // string存的字符串
		size_t _size; // string中字符串的长度 
		size_t _capacity; // string的容量
		static const size_t npos = -1;
	};

	inline ostream& operator<<(ostream& out, const string& str)
	{
		int len = str._size;
		for (int i = 0; i < len; i ++ )
		{
			out << str._str[i];
		}
		return out;
	}
	inline istream& operator>>(istream& in, string& str)
	{
		str.clear();
		char ch = in.get();
		char buff[128];
		int i = 0;
		while (ch != ' ' && ch != '\n')
		{
			buff[i ++ ] = ch;
			if (i == 127)
			{
				buff[i] = '\0';
				str += buff;
				i = 0;
			}
			ch = in.get();
		}

		if (i != 0)
		{
			buff[i] = '\0';
			str += buff;
		}
		return in;
	}
}

谢谢大家!

相关推荐
易码智能几秒前
【EtherCATBasics】- KRTS C++示例精讲(2)
开发语言·c++·kithara·windows 实时套件·krts
一只自律的鸡1 分钟前
C语言项目 天天酷跑(上篇)
c语言·开发语言
程序猿000001号4 分钟前
使用Python的Seaborn库进行数据可视化
开发语言·python·信息可视化
ཌ斌赋ད7 分钟前
FFTW基本概念与安装使用
c++
一个不正经的林Sir9 分钟前
C#WPF基础介绍/第一个WPF程序
开发语言·c#·wpf
API快乐传递者13 分钟前
Python爬虫获取淘宝详情接口详细解析
开发语言·爬虫·python
公众号Codewar原创作者15 分钟前
R数据分析:工具变量回归的做法和解释,实例解析
开发语言·人工智能·python
赵钰老师18 分钟前
基于R语言APSIM模型应用及批量模拟(精细农业、水肥管理、气候变化、粮食安全、土壤碳周转、环境影响、农业可持续性、农业生态等)
开发语言·数据分析·r语言
lly20240635 分钟前
Highcharts 饼图:数据可视化利器
开发语言
薄荷故人_39 分钟前
从零开始的C++之旅——红黑树封装map_set
c++