string类

一、string类对象的常用接口

1.1 string类对象的常用构造

函数名称功能
string()
构造空的string类对象,即空字符串
string(const char* s)
用C格式字符串来构造string类对象
string(size_t n, char c)
string类对象中包含n个字符c
string(const string&s)
拷贝构造函数
int main()
{
	string s1;//构造空的string类对象s1
	string s2("hello world");//用C格式字符串构造string类对象s2

	string s3(s2);//拷贝s2构造s3
	string s4 = s2;//拷贝s2构造s4,和s3效果相同

	string s5("hello world", 4);
	//s5取"hello world"前4个,即s5 = "hell"

	string s6(10,'s');
	//s6取10个s,即s6 = "ssssssssss"

	string s7(s2, 6, 3);
	//s7从s2的第6个开始往后取3个,即s7 = "wor"

	string s8(s2, 6, 200);
	//s8从s2的第6个开始往后取200个,超出范围则到结尾止,即s8 = "world"

	string s9(s2, 6);
	//s9从s2的第6个开始往后取,直到结尾止,即s9 = "world"

	cout << "s1:" << s1 << endl;
	cout << "s2:" << s2 << endl;
	cout << "s3:" << s3 << endl;
	cout << "s4:" << s4 << endl;
	cout << "s5:" << s5 << endl;
	cout << "s6:" << s6 << endl;
	cout << "s7:" << s7 << endl;
	cout << "s8:" << s8 << endl;
	cout << "s9:" << s9 << endl;

	return 0;
}

1.2 string类对象的容量操作

函数名称功能
size
返回字符串有效字符长度
length
返回字符串有效字符长度
capacity
返回空间总大小
empty
检测字符串释放为空串,是返回true,否则返回false
clear
清空有效字符
reserve
为字符串预留空间**
resize
将有效字符的个数该成n个,多出的空间用字符c填充
int main()
{
	//string类对象支持用cin和cout进行输入、输出
	string s1("hello world");
	string s2;
	string s3 = "hello world";
	string s4 = s3;
	string s5 = s3;
	//可以直接赋值
	s2 = "hello world";

	cout << s1.size() << endl;
	cout << s1.length() << endl;
	cout << s1.capacity() << endl;
	cout << s1.empty() << endl;

	//clear将字符串清空,即将size清0,但不改变底层空间(capacity)
	s1.clear();
	cout << s1 << endl;
	cout << s1.size() << endl;//清为0
	cout << s1.capacity() << endl;//不变


	//resize将s2的有效字符数(size)变成20个,多出的位置用'c'来填充
	s2.resize(20, 'c');
	//s2: "hello world" -> "hello worldccccccccc"
	cout << s2 << endl;
	cout << s2.size() << endl;// 11 -> 20

	//resize将s3的有效字符数(size)变成20个,多出的位置用'\0'来填充
	s3.resize(20);
	//s3: "hello world" -> "hello world\0\0\0\0\0\0\0\0\0"
	cout << s3 << endl;
	cout << s3.size() << endl;// 11 -> 20

	//resize将s4的有效字符数(size)变成5个
	s4.resize(5);
	//s4: "hello world" -> "hello"
	cout << s4 << endl;
	cout << s3.size() << endl;// 11 -> 5

	//reverse不会改变string中有效元素个数(size)
	//reserve参数小于string的底层空间(capacity)大小时,空间不会缩小
	s5.reserve(5);
	cout << s5.size() << endl;
	cout << s5.capacity() << endl;

	//reserve参数大于string的底层空间(capacity)大小时,空间才会扩大
	s5.reserve(100);
	cout << s5.size() << endl;
	cout << s5.capacity() << endl;

	return 0;
}

注意点:

  1. size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()
  2. clear()只是将string中有效字符清空,不改变底层空间大小。
  3. resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用'\0'来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。
  4. reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserver不会改变容量大小。
  5. reserve 是扩空间,resize是扩空间+初始化
  6. VS下,reserve和resize都不会缩容量(capacity)

1.3 string类对象的访问及遍历操作  

int main()
{
	//遍历s1的每一个字符
	string s1("hello world");
	string s2 = "xxxxxx";

	//第一种方式:下标+[]
	for (size_t i = 0; i < s1.size(); i++)
	{
		cout << s1[i] << " ";
	}
	cout << endl;

	//第二种方式:迭代器(是一个像指针一样的东西)
	string::iterator it = s1.begin();
	while (it != s1.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;

	//第三种方式:范围for , 原理:系统自动替换成迭代器
	for (auto ch : s1)
	{
		cout << ch << " ";
	}
	cout << endl;

	//访问方式,和C差不多
	s1[0];// 'h'
	s1[0] = 'c';// 'h' -> 'c'


	//迭代器还分正向和反向
	//正向迭代器,从前往后
	string::iterator it = s1.begin();
	while (it != s1.end())
	{
		(*it) += 1;//可以修改字符串内容

		cout << *it << endl;
		it++;
	}
	cout << endl;

	//反向迭代器,从后往前
	string::reverse_iterator rit = s1.rbegin();
	while (rit != s1.rend())
	{
		(*rit) += 1;

		cout << *rit << endl;
		rit++;
	}
	cout << endl;

	s1.swap(s2);//效率高,交换指针
	swap(s1, s2);//效率低,深拷贝

	return 0;
}

1.4 string类对象的修改操作

函数名称功能
push_back
在字符串后尾插 字符 c(不是字符串)
append
在字符串后追加一个字符串
operator+=
在字符串后追加字符串str
c_str
  返回C格式字符串 
 rfind  
 从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置  
 substr  
 在str中从pos位置开始,截取n个字符,然后将其返回  
int main()
{
	string s1("hello world");
	s1.push_back('!');//在s1后面插入'!'
	s1.append("!!");//在s1后面插入"!!"
	s1 += '!';//在s1后面插入'!'
	s1 += "!!";//在s1后面插入"!!"

	cout << s1 << endl;
	cout << s1.c_str() << endl;//以C语言格式打印字符串

	//读取test.cpp的后缀
	string s2("test.cpp");
	size_t pos = s2.rfind('.');
	//find是从前往后找
	//rfind是从后往前找

	string s(s2.substr(pos, s2.size() - pos));
	//substr:
	//在s2中从pos位置开始,截取[s2.size()-pos]个字符,然后将其返回  
	cout << s << endl;

	return 0;
}

二、string类的模拟实现

2.1 实现一个string,只考虑资源管理深浅拷贝问题,暂且不考虑增删查改

//深拷贝
namespace Cris
{
	class string
	{
	public:
		string(const char* str)
			:_str(new char[strlen(str)+1])
		{
			strcpy(_str, str);
		}

		string(const string& s)
			:_str(new char[strlen(s._str)+1])
		{
			strcpy(_str, s._str);
		}

		string& operator=(const string& s)
		{
			if (this != &s)
			{
				char* tmp = new char[strlen(s._str) + 1];
				strcpy(tmp, s._str);
				delete[] _str;
				_str = tmp;
			}

			return *this;
		}

	private:
		char* _str;
	};
}

 2.2 string类的模拟实现

namespace Cris
{
	class string
	{
	public:

		//全缺省
		string(const char* str = "")
			:_size(strlen(str))
			, _capacity(_size)
		{
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}


		//传统写法:老老实实该开空间开空间,该拷贝数据自己拷贝数据
		/*string(const string& s)
			:_size(strlen(s._str))
			, _capacity(_size)
		{
			_str = new char[_capacity + 1];
			strcpy(_str, s._str);
		}*/

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

		//现代写法:要完成深拷贝,自己不想干活,安排别人干活,然后窃取劳动成果
		string(const string& s)
			:_str(nullptr)
			,_size(0)
			,_capacity(0)
		{
			//将s._str拷贝到tmp
			string tmp(s._str);
			//tmp与this交换指针,剥夺劳动成果
			swap(tmp);
		}

		string& operator=(const string& s)
		{
			if (this != &s)
			{
				char* tmp = new char[s._capacity + 1];
				strcpy(tmp, s._str);
				delete[] _str;
				_str = tmp;
				_size = s._size;
				_capacity = s._capacity;
			}

			return *this;
		}

		~string()
		{
			if (_str)
			{
				delete[] _str;
				_str = nullptr;
				_size = _capacity = 0;
			}
		}

		const char* c_str() const
		{
			return _str;
		}

		char& operator[](size_t pos)
		{
			assert(pos < _size);
			return _str[pos];
		}

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

		size_t size() const
		{
			return _size;
		}

		size_t capacity() const
		{
			return _capacity;
		}

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

		string& operator+=(char ch)
		{
			push_back(ch);
			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;
			}
		}

		//扩空间+初始化
		//删除部分数据,保留前n个
		void resize(size_t n, char ch = '\0')
		{
			if (n < _size)
			{
				_size = n;
				_str[_size] = '\0';
			}
			else
			{
				if (n > _capacity)
				{
					reserve(n);
				}

				for (size_t i = _size; i < n; i++)
				{
					_str[i] = ch;
				}
				_size = n;
				_str[_size] = '\0';
			}
		}

		void push_back(char ch)
		{
			/*if (_size == _capacity)
			{
				reserve(_capacity == 0 ? 4 : _capacity * 2);
			}
			_str[_size] = ch;
			++_size;
			_str[_size] = '\0';*/

			insert(_size, ch);
		}

		void append(const char* str)
		{
			//size_t len = _size + strlen(str);
			//if (len > _capacity)
			//{
			//	reserve(len);
			//}

			    //_str是字符串首地址
				//_str + _size是字符串尾地址
				//strcpy(_str + _size, str);
				//_size = len;

				insert(_size, str);
		}


		//插入字符
		string& insert(size_t pos, char ch)
		{
			assert(pos <= _size);
			if (_size == _capacity)
			{
				reserve(_capacity == 0 ? 4 : _capacity * 2);
			}

			size_t end = _size + 1;
			while (end > pos)
			{
				_str[end] = _str[end - 1];
				end--;
			}

			_str[pos] = ch;
			_size++;

			return *this;
		}


		//插入字符串
		string& insert(size_t pos, const char* str)
		{
			assert(pos <= _size);

			size_t len = strlen(str);
			if (_size + len > _capacity)
			{
				reserve(_size + len);
			}


			//往后挪动len个位置
			size_t end = _size + len;
			while (end > pos + len - 1)
			{
				_str[end] = _str[end - len];
				--end;
			}

			strncpy(_str + pos, str, len);
			_size += len;

			return *this;
		}

		string& erase(size_t pos, size_t len = npos)
		{
			assert(pos < _size);

			if (len == npos || pos + len >= _size)
			{
				_str[pos] = '\0';
				_size = pos;
			}
			else
			{
				size_t begin = pos + len;
				while (begin <= _size)
				{
					_str[begin - len] = _str[begin];
					++begin;
				}

				_size -= len;
			}

			return *this;
		}

		//在字符串中找字符
		size_t find(char ch, size_t pos = 0)
		{
			for (; pos < _size; pos++)
			{
				if (_str[pos] = ch)
					return pos;
			}

			return npos;
		}

		//在字符串中找字符串
		size_t find(const char* str, size_t pos = 0)
		{
			//strstr:在字符串_str+pos中找字符串str
			const char* p = strstr(_str + pos, str);
			if (p == nullptr)
			{
				return npos;
			}
			else
			{
				return p - _str;
			}
		}

	private:
		char* _str;
		size_t _size;//有效字符个数
		size_t _capacity;//实际存储有效字符的空间

		const static size_t npos;
	};
}

const size_t string::npos = -1;

ostream& operator<<(ostream& out, const string& s)
{
	for (auto ch : s)
	{
		out << ch;
	}

	return out;
}

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

	//return in;

	char ch;
	ch = in.get();
	char buff[128] = { '\0' };
	size_t i = 0;

	//满128个放进去一次,提高效率
	while (ch != ' ' && ch != '\n')
	{
		buff[i++] = ch;
		if (i == 127)
		{
			s += buff;
			memset(buff, '\0', 128);
			i = 0;
		}

		ch = in.get();
	}

	s += buff;
	return in;
}

bool operator<(const string& s1, const string& s2)
{
	return strcmp(s1.c_str(), s2.c_str()) < 0;
}

bool operator==(const string& s1, const string& s2)
{
	return strcmp(s1.c_str(), s2.c_str()) == 0;
}

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

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

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

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

  • 31
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 30
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 30
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cristiano777.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值