C++学习之STL(2):string的解析与模拟实现

本文深入介绍了C++中的string类,包括其作为面向对象的字符串处理方式,避免了C语言中可能出现的越界问题。文章详细阐述了string类的重要函数接口,如构造函数、容量操作、访问与遍历、修改操作等,并给出了一个简单的模拟实现,展示了如何从零开始构建一个具备基本功能的string类。此外,还探讨了string类的非成员函数,如字符串拼接、输入输出操作等。
摘要由CSDN通过智能技术生成

一级目录:string类的介绍

1.我们已经在c语言中学习了关于字符串函数的许多重要函数例如:strcpy(字符串拷贝函数),strcmp(字符串比较函数)等等可以实现我们想要的操作,但是在C++中,我们为了实现面向对象的思想,并且底层空间让用户自己保管,用c语言中的库函数有可能出现越界访问的存在。
2.经过我的简单介绍,我们来看看文档中对string类的介绍吧:

  1. 字符串是表示字符序列的类
  2. 标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作
    单字节字符字符串的设计特性。
  3. string类是使用char(即作为它的字符类型,使用它的默认char_traits和分配器类型(关于模板的更多信
    息,请参阅basic_string)。
  4. string类是basic_string模板类的一个实例,它使用char来实例化basic_string模板类,并用char_traits
    和allocator作为basic_string的默认参数(根于更多的模板信息请参考basic_string)。
  5. 注意,这个类独立于所使用的编码来处理字节:如果用来处理多字节或变长字符(如UTF-8)的序列,这个
    类的所有成员(如长度或大小)以及它的迭代器,将仍然按照字节(而不是实际编码的字符)来操作。

二级目录:string类使用的重要函数接口及功能

1.首先,我们在使用string类中的函数时,必须先引进头文件

#include<string>

2.string类对象的常见构造如下

string()//构造一个空对象,即空字符串
string(const char* s)//通过字符串s构造一个string类对象
string(size_t n,char c)//构造一个含有n个字符为c的string类对象
string(const string& s)//通过一个实例化的string类s去拷贝构造一个新string类

3.string类容量的基本操作函数接口:

size()//返回字符串的有效字符长度
length()//返回字符串的有效字符长度
capacity()//返回字符串的总空间大小
empty()//判断字符串是否为空
clear()//清空有效字符
reserve(size_t n = 0)//为字符串预留空间(自己设置初始字符串的容量,为n的大小)
resize(size_t n)//将字符串长度改变(自己设置缩小字符串的大小)为n的大小
resize(size_t n,char c)//使用方法和上面一样,不同的是扩大的时候,上面的函数会对新增的空间自动赋为0,而此函数赋为字符c。

其中:
①.size和length的用法是相同的,一般为了与其他容器接口相同,我们一般使用的是size.
②.clear是清理字符串中的有效字符,与底层的空间容量无关。
③.resize函数在进行扩容时,底层空间容量可能会改变,但是缩小不会改变。
④.reserve函数,它不会改变已存在有效元素的个数,当reserve的参数小于
string的底层空间总大小时,reserver不会改变容量大小。

4.string类对象的访问及遍历操作函数接口:

const_reference operator[](size_type pos) const;
reference operator[](size_type pos);//这两个函数接口都是访问string类中的字符串的某个位置的数据,与数组的使用方法相似,是重载了[]的使用方法。
iterator begin();//迭代器的使用,指的是有效字符的第一个位置,一般是下表为0的位置。
iterator end();//迭代器的使用,指得是最后一个有效字符的下一个位置,一般情况下是’\0‘的位置

5.string类对象的修改操作函数接口:

void push_back (char c)//在字符串后插一个字符c
void push_front(char c)//在字符串的头插一个字符c
string& append (const string& str);//在字符串后追加一个字符串
string& operator+= (const string& str);//在字符串后追加字符串
const char* c_str() const;//返回一个c格式字符串,可以用cout输出
size_t find (const string& str, size_t pos = 0) const;//从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置
size_t rfind (const string& str, size_t pos = npos) const;//从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置
string substr (size_t pos = 0, size_t len = npos) const;//在str中从pos位置开始,截取n个字符,然后将其返回

6.string类非成员函数

string operator+ (const string& lhs, const string& rhs);//将两个字符串相加,但是它是传值返回,效率比较低下。
istream& operator<< (istream& is, string& str);//重载输出符号,可以直接通过cout输出string类的字符串
istream& operator>> (istream& is, string& str);//重载输入符号,可以直接通过cin输入string类的字符串
istream& getline (istream& is, string& str);//获取一行字符串

三级目录:string类的模拟实现

#include<iostream>
using namespace std;
namespace My_string
{
	class string
	{
	public:
		typedef char* iterator;
		friend ostream& operator<<(ostream& _cout, const My_string::string& s);
		friend istream& operator>>(istream& _cin, My_string::string& s);
	//四大函数均采用现代的做法
	public:
		string(const char* str = "")//构造函数
		{
			m_capacity = m_size = strlen(str);
			m_str = new char[m_capacity + 1];
			strcpy(m_str, str);
		}
		string(const string &str) :m_str(nullptr), m_capacity(0), m_size(0)//拷贝构造函数
		{
			string str_tmp(str.m_str);
			this->Swap(str_tmp);
		}
		string& operator=(string str)//赋值语句
		{
			this->Swap(str);
			return *this;
		}
		~string()//析构函数
		{
			if (m_str)
			{
				m_capacity = m_size = 0;
				delete[] m_str;
				m_str = nullptr;
			}
		}
	//迭代器部分
	public:
		iterator begin()
		{
			return (iterator)m_str;
		}
		iterator end()
		{
			return (iterator)m_str[m_size];
		}
	//修改部分(modify)
	public:
		void push_back(char c)
		{
			//判断是否扩容;
			if (m_size == m_capacity)
			{
				reserve(2 * m_capacity + 1);
			}
			//尾加字符
			m_str[m_size++] = c;
			m_str[m_size] = '\0';
		}
		string& operator+=(char c)
		{
			push_back(c);
			return *this;
		}
		void append(const char* str)
		{
			size_t len = strlen(str);
			while(len + m_size > m_capacity)
				reserve(2 * m_capacity + 1);
			strcpy(m_str+m_size, str);
			m_size += len;
		}
		string& operator+=(const char* str)
		{
			append(str);
			return *this;
		}
		void clear()
		{
			m_size = 0;
			m_str[m_size] = '\0';
		}
		const char* c_str()const
		{
			return m_str;
		}
		//容量部分
	public:
		size_t size()
		{
			return m_size;
		}
		size_t capacity()
		{
			return m_capacity;
		}
		bool empty()
		{
			return m_size == 0;
		}
		void resize(size_t newSize, char c = '\0')
		{
			if (newSize > m_size)
			{
				// 如果newSize大于底层空间大小,则需要重新开辟空间
				if (newSize > m_capacity)
				{
					reserve(newSize);
				}
				memset(m_str +m_size, c, newSize - m_size);
			}
			m_size = newSize;
			m_str[newSize] = '\0';
		}
		void reserve(size_t New_capacity)
		{
			if (New_capacity > m_capacity)
			{
				char* str = new char[New_capacity];
				strcpy(str, m_str);
				//释放原来空间使用新空间
				delete[] m_str;
				m_str = str;
				m_capacity = New_capacity;
			}
		}
	public:
		char& operator[](size_t index)
		{
			if (index < m_size)
			    return m_str[index];
		}
		const char& operator[](size_t index)const
		{
			if (index < m_size)
				return m_str[index];
		}
		bool operator<(const string& s)
		{
			return strcmp(m_str, s.m_str) > 0;
		}
		bool operator<=(const string& s)
		{
			return strcmp(m_str, s.m_str) <= 0;
		}
		bool operator>(const string& s)
		{
			return strcmp(m_str, s.m_str) > 0;
		}
		bool operator>=(const string& s)
		{
			return strcmp(m_str, s.m_str) >= 0;
		}
		bool operator==(const string& s)
		{
			return strcmp(m_str, s.m_str) == 0;
		}
		bool operator!=(const string& s)
		{
			return strcmp(m_str, s.m_str) != 0;
		}
		//返回字符c出现在string中的第一个位置
		size_t find(char c, size_t pos = 0) const
		{
			for (int i = pos; i < m_size; ++i)
			{
				if (m_str[i] == c)
					return i;
			}
			return -1;
		}
		//返回字符串s出现在string中的第一个位置
	    size_t find(const char* s, size_t pos = 0) const
		{
			for (int i = 0; i < m_size; ++i)
			{
				if (m_str[i] == s[0])
				{
					int count = i;
					int j = 0;
					for (; j < strlen(s) && count < m_size; ++j,++count)
					{
						if (m_str[count] != s[j])
							break;
					}
					if (j == strlen(s))
						return i;
				}
			}
			return -1;
		}
		//在pos位置上插入字符c,并返回该字符的位置
		string& insert(size_t pos, char c)
		{
			//判断容量是否够;
			if (m_size + 1 > m_capacity)
			{
				reserve(2 * m_capacity + 1);
			}
			//插入数据
			for (int i = m_size - 1; i >= pos; --i)
			{
				m_str[i+1] = m_str[i];
			}
			m_str[pos] = c;
			m_size++;
			m_str[m_size] = '\0';
			return *this;
		}
		//在pos位置上插入字符串str,并返回该字符的位置
		string& insert(size_t pos, const char* str)
		{
			int len = strlen(str);
			//判断是否扩容
			while (m_size + len > m_capacity)
			{
				reserve(2 * m_capacity + 1);
			}
			//插入字符串
			for (int i = m_size - 1; i >= pos; --i)
				m_str[i+3] = m_str[i];
			for (int i = 0; i < len; ++i)
			{
				m_str[pos] = str[i];
				pos++;
			}
			m_size += len;
			m_str[m_size] = '\0';
			return *this;
		}
		// 删除pos位置上的元素,并返回该元素的下一个位置
		string& erase(size_t pos)
		{
			for (int i = pos; i < m_size; ++i)
			{
				m_str[i] = m_str[i + 1];
			}
			m_str[--m_size] = '\0';
			return *this;
		}

	public:
		void Swap(string &str)
		{
			swap(m_str, str.m_str);
			swap(m_capacity, str.m_capacity);
			swap(m_size, str.m_size);
		}
	private:
		char* m_str;
		size_t m_capacity;
		size_t m_size;
	};
	ostream& operator<<(ostream& out, const My_string::string& s)
	{
		for (int i = 0; i < s.m_size; ++i)
			out << s.m_str[i];
		return out;
	}
	istream& operator>>(istream& in, My_string::string& s)
	{
		while (1)
		{
			char c;
			c = in.get();
			if (c == '\0' || c == ' ')
				break;
			else
			{
				s.push_back(c);
			}
			return in;
		}
	}
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值