C++ —— string类的实用接口

1.string类简介

现在用法是将string类当成STL用,但实际上string类与STL并没有关系。事实上C语言的标准库配套了str系列的字符串函数,可惜这些函数跟字符串本身是分离开的,那么就不符合面向对象的思想。

所以在C++中,直接把字符串归成了一个类来管理,也就是说string类是属于C++的标准库的。那么string类设计了诸多有用的公用接口以及各类的函数重载,如果真要从头数到尾估计有一两百个吧(我没数过,瞎猜的)。string类是一个模板的实例,这样的设计呢是因为编码的存在

编码就是类似于ASCLL码的这样的一套用来表示字符的规则,计算机是美国人发明的,那么理所应当编码只能表示数字和英文。但随着计算机的发展,人对于计算机的要求越来越高,那么编码只支持英文就不太合适了,所以就诞生出了诸多编码,而我们使用string类的原生模板的实例化类型是char,因为它使用的编码是utf-8,简单来说,这套编码不仅支持数字和英文,还支持汉字。

因为string是专门管理字符串的,所以很多的设计思维不能同其他容器那样,就比如我们要统计字符串的大小时通常指的是有效字符的长度,而其他数据却考虑的不是长度,而是这些数据所占据的空间。所以为了设计上的统一,绝大部分的接口设计与其他容器的接口相同。

因为string类是标准库里面的东西,所用使用string类的时候要添加头文件 <string>并且还要放开命名空间

2.实用容量接口

我们知道描述字符串的大小通常是以长度来描述的,所以在早期的string中是有一个专门的函数用来返回字符串长度的公用接口函数的:

	string s1 = "Nice to meet you.";
	int len = s1.length();//返回字符串长度的函数
	cout << len << endl;

但是后来由于STL的引入,就造成了string的接口与其他容器格格不入,所以添加了 size() 这个功能与 length() 完全一致的函数,其目的就是为了向其他容器统一

	string s1 = "Nice to meet you.";
	//int len = s1.length();//返回字符串长度的函数
	int len = s1.size();
	cout << len << endl;

string类还提供了可以改变有效字符的个数的函数,这样的函数有两个,分别为 clear()和 resize()。注意:这两个函数是改变有效字符个数的函数,而不是改变其容量大小的函数

事实上我更推荐大家使用resize(),因为resize()需要我们手动添加一个参数,将这个参数置0与clear()的效果是一样的。并且resize()不仅能够减小有效字符的个数,还能自定义添加有效字符的个数:

	string s2 = "hello world";
	s2.resize(6);//s2的有效字符个数为6
	int sz = s2.size();
	s2.resize(9, 'c');//增加有效字符个数
	//对比之前多出来的几个有效字符,我们可以指定它
	cout << s2 << endl;

在这里插入图片描述
因为有效字符个数的改变,那么其必定会影响容量大小。影响的行为为:当resize()添加有效字符个数时,如果超出了容量的范围,那么容量就会进行扩容

	string s3 = "1234";
	int sz = s3.size();
	cout << "当前size为:" << sz << " " << "初始容量为:" << s3.capacity() << endl;

	while (s3.capacity() < 1000)
	{
		int tmp = s3.capacity();
		sz += 20;
		s3.resize(sz);
		if (tmp != s3.capacity())
		{
			cout << "当前size为:"<<sz<<" " << "容量改变为:" << s3.capacity() << endl;
		}
	}
}

在这里插入图片描述
Visua Studio 2022 环境下,容量呈1.5倍增长

但是当有效字符个数减少时,容量是不会改变的:

	string s3 = "1234";
	int sz = s3.size();
	sz += 1000;
	s3.resize(sz);
	while (sz > 0)
	{
		sz -= 50;
		cout << "当前size为:" << sz << " " << "容量为:" << s3.capacity() << endl;
	}

在这里插入图片描述

3.实用遍历方式

对于string来说,正常的遍历有三种:

	string s4 = "12345";
	
	//遍历方式1:使用 [] 运算符重载
	for (int i = 0; i < s4.size(); i++)
	{
		cout << s4[i] << " ";
	}
	cout << endl;

	//遍历方式2:使用范围for
	for (auto& tmp : s4)
	{
		cout << tmp << " ";
	}
	cout << endl;

	//遍历方式3:使用迭代器
	for (auto i = s4.begin(); i < s4.end(); i++)
	{
		cout << *i << " ";//迭代器的行为可以是指针
		//使用的时候当成指针用就可以
	}
	cout << endl;

事实上我更推荐用迭代器遍历,因为这样可以与其他容器匹配。因为对于list容器,如果我么使用 [] 运算符重载的方式遍历,这种感觉就很怪。但是在实际使用的时候用的最多的还是[]运算符重载。

如果我们想要倒序输出的话就可以使用反向迭代器了

	for (auto i = s4.rbegin(); i < s4.rend(); i++)
	{
		cout << *i << " ";
	}
	cout << endl;

4.实用修改接口

我们模拟实现过顺序表,尾插的话会实用PushBack()函数,stirng也有这个函数:

	string s5 = "hello ";
	s5.push_back('w');
	s5.push_back('o');
	//……

但是这样只能每次只能尾插一个字符,这就很累赘了。所以我们用的最多的便是 +=运算符重载

	string s5 = "hello ";
	s5 += "world";
	cout << s5 << endl;

在这里插入图片描述
我个人觉得最实用的还得是find()接口。其作用是寻找对应的字符,找到了就返回对应的位置,找不到就返回npos。我们实用简单的代码来描述这个接口的功能:

	string s6 = "Nice to meet you.";
	int prev_pos = 0;
	int after_pos = 0;
	while ((after_pos = s6.find(" ", after_pos)) != string::npos)
	{
		/*for (auto i = s6.begin() + prev_pos; i < s6.begin() + after_pos; i++)
		{
			cout << *i;
		}
		cout << endl;*/
		
		cout << s6.substr(prev_pos, after_pos - prev_pos) << endl;
		prev_pos = ++after_pos;
	}
	cout << s6.substr(prev_pos, after_pos - prev_pos) << endl;

在这里插入图片描述
有这样的工具那就来做一道题:反转字符串中的单词
在这里插入图片描述

class Solution {
public:
    string reverseWords(string s) {
        int prev_pos=0;
        int after_pos=0;
        while((after_pos=s.find(" ",after_pos))!=string::npos)
        {
            reverse(s.begin()+prev_pos,s.begin()+after_pos);
            prev_pos=++after_pos;
        }
        reverse(s.begin()+prev_pos,s.end());
        return s;
    }
};
  • 14
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小龙向钱进

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

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

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

打赏作者

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

抵扣说明:

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

余额充值