• 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;
    
    • 1
    • 2
    • 3

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

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

    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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述
    因为有效字符个数的改变,那么其必定会影响容量大小。影响的行为为:当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;
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述
    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;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

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

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

    	for (auto i = s4.rbegin(); i < s4.rend(); i++)
    	{
    		cout << *i << " ";
    	}
    	cout << endl;
    
    • 1
    • 2
    • 3
    • 4
    • 5

    4.实用修改接口

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

    	string s5 = "hello ";
    	s5.push_back('w');
    	s5.push_back('o');
    	//……
    
    • 1
    • 2
    • 3
    • 4

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

    	string s5 = "hello ";
    	s5 += "world";
    	cout << s5 << endl;
    
    • 1
    • 2
    • 3

    在这里插入图片描述
    我个人觉得最实用的还得是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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

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

    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;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
  • 相关阅读:
    数字图像处理 基于numpy库的傅里叶变换
    【SA8295P 源码分析】121 - MAX9295A 加串器芯片手册分析 及初始化参数分析
    未来三年「超千万辆」市场空间,行泊一体赛道进入甜蜜期
    mysql的小数操作
    C语言编程题(四)有符号数与无符号数相加
    前端npm详解
    前端 js面试题(二)
    多旋翼无人机组合导航系统-多源信息融合算法(Matlab代码实现)
    香港 Web3 的分岔路口:to 创新 or to 监管,这并不是一个问题
    全栈自动化测试之 python基础语法介绍
  • 原文地址:https://blog.csdn.net/weixin_59913110/article/details/127569217