• string容器的常用操作


    一、C语言中的字符串

    在C语言中,字符串是以\0结尾的一串字符的集合,而为了操作方便,C标准库中提供了一些str系列的库函数,比如,strcpy、strlen、strcmp等等。但是这些库函数与字符串是分离开的,不太符合OOP的思想(面向对象编程(Object Oriented Programming)),而且底层空间需要用户自己管理,稍不留神可能就会有越界访问的问题发生。

    二、string容器

    1、概念

    string容器是c++中表示字符序列的一个类,同时也是一个类模板。它提供了许多成员函数和运算符重载,封装了C++中对字符串的常见操作和功能,提供了更高级的字符串处理能力,并且隐藏了底层的实现细节,使得字符串的操作更加方便和安全。但string类是一个泛型类,它是由模板实例化出来的一个标准类,本质上不是一个标准数据类型。详情参见上方string容器文档。

    2、特点

    • 标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作单字节字符和字符串的设计特性。
    • string类是basic_string模板类的一个实例,它使用char作为basic_string模板类的类型去实例化,并用char_traits和allocator作为basic_string的默认参数(模板的概念参见模板和STL简介)。
    • string类处理字节与使用的编码无关。即如果用于处理多字节或可变长度字符(如 UTF-8)的序列,则此类的所有成员(如长度或大小)及其迭代器仍将以字节(而不是实际编码字符)为单位运行。
    • 在使用string类时,必须用#include包含它的头文件string以及使用标准命名空间std。

    三、string类对象的常见构造

    1、构造

    常用构造函数名称功能说明
    string()创建一个空的string类对象,即空字符串
    string(const char* s)用C语言格式的字符串来构造string类对象
    string(size_t n, char c)创建一个包含n个字符c的string类对象
    string(const string& str)string类的拷贝构造函数,用对象str创建一个string类对象

    2、实际构造函数

    在这里插入图片描述

    3、测试代码

    #include
    #include
    using namespace std;
    
    void Test_string1()
    {
        string s1;
        cout << s1 << endl;
    
        string s2("snow dragon");
        cout << s2 << endl;
    
        string s3(6, 's');
        cout << s3 << endl;
    
        string s4(s2);
        cout << s4 << endl;
    }
    
    int main()
    {
    	try
    	{
    		Test_string1();
    	}
    	catch (const std::exception& e)
    	{
    		cout << e.what() << endl;
    	}
    	
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • main函数中的try与catch的作用是捕获异常。

    4、运行结果

    在这里插入图片描述

    四、赋值运算符

    1、类型

    在这里插入图片描述

    2、作用

    =运算符用一个新值为string对象的字符串赋值,它会替换掉string对象字符串之前的内容。

    3、测试代码

    int main()
    {
    	string s1;
    	string s2 = "snow dragon"; // 调用构造函数 + 拷贝构造 -> 编译器优化 --> 直接调用构造函数创建对象s2
    	
    	cout << s1 << endl;
    	cout << s2 << endl;
    
    	s1 = s2;
    	cout << s1 << endl;
    
    	s1 = "ssss";
    	cout << s1 << endl;
    
    	s1 = 's';
    	cout << s1 << endl;
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    4、运行结果

    在这里插入图片描述

    五、string类对象的容量操作

    1、成员函数

    函数名称功能说明
    size_t size() const;返回字符串的长度(以字节为单位)。
    size_t capacity() const;返回当前为字符串分配的存储空间的大小,以字节表示。
    bool empty() const;返回字符串是否为空,即其长度是否为 0。
    void clear();擦除字符串的内容,该字符串将成为空字符串(长度为 0 个字符)。
    void reserve (size_t n = 0);请求更改容量的大小,对字符串(对象)长度没有影响,并且无法更改其内容。
    void resize (size_t n);void resize (size_t n, char c);将字符串的大小调整为n个字符的长度,即修改size。

    2、测试代码

    void Test_string2()
    {
        string s1("snow");
        cout << s1 << endl;
        cout << s1.size() << endl;
        cout << s1.capacity() << endl;
        cout << s1.empty() << endl;
    
        cout << "***************************" << endl;
    
        string s2;
        cout << s2.empty() << endl;
    
        cout << "***************************" << endl;
    
        string s3("snow");
        cout << s3 << endl;
        cout << s3.size() << endl;
        s3.resize(10, '!');
        cout << s3 << endl;
        cout << s3.size() << endl;
        s3.resize(3);
        cout << s3 << endl;
        cout << s3.size() << endl;
    
        cout << "***************************" << endl;
    
        string s4;
        s4.reserve(100);
        cout << s4.size() << endl;
        cout << s4.capacity() << endl;
    
        s4.reserve(50);
        cout << s4.size() << endl;
        cout << s4.capacity() << endl;
    
        cout << "***************************" << endl;
    
        s1.clear();
        cout << s1 << endl;
        cout << s1.size() << endl;
        cout << s1.capacity() << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    3、说明

    • string类对象的容量操作函数中其实还有函数size_t length() const。只不过它不常用,并且size()与length()函数的底层实现原理完全相同,这里引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是使用函数size()。
    • 函数clear()只是将string中有效字符清空,即将string对象中的字符串清空时,只是将size置为0,但不改变对象的底层空间大小。
    • resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)是用0来对多出的空间的元素进行赋值,resize(size_t n, char c)是用字符c来对多出的空间的元素进行赋值。
    • resize在改变元素个数时,如果是将元素个数增多,可能会改变容量空间的大小,如果是将元素个数减少,则它的容量空间不会改变。
    • reserve(size_t res_arg=0);的作用是为string对象预留空间,它不改变有效元素个数,即对容量空间大小进行处理。但当reserve的参数小于string的容量空间总大小时,reserver不会改变容量空间的大小。

    4、运行结果

    在这里插入图片描述

    六、运算符[]

    1、类型

    在这里插入图片描述

    2、作用

    返回string对象字符串下标为pos的字符的引用。

    3、测试代码

    void Test2()
    {
    	string s1("snow dragon");
    	cout << s1[0] << endl;
    	cout << s1 << endl;
    
    	s1[0] = 'h';
    	cout << s1[0] << endl;
    	cout << s1 << endl;
    
    	//遍历string对象并对它的每个字符+1
    	for (size_t i = 0; i < s1.size(); ++i)
    	{
    		s1[i]++;
    	}
    	cout << s1 << endl;
    
    	const string s2("dragon");
    	for (size_t i = 0; i < s2.size(); ++i)
    	{
    		//s2[i]++;
    		cout << s2[i] << " ";
    	}
    	cout << endl;
    	cout << s2 << endl;
    
    	//cout << s2[10] << endl;			//编译器内部会检查是否越界
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    4、运行结果

    在这里插入图片描述

    5、错误代码与编译器报错

    在这里插入图片描述

    七、迭代器

    1、类型

    在这里插入图片描述

    2、概念

    迭代器是一种检查容器内的元素并遍历元素的数据类型,通常用于对C++中各种容器内的元素进行访问。

    3、测试代码

    void Test3()
    {
    	cout << "s1 test" << endl;
    	string s1("snow");
    	cout << s1 << endl;
    	string::iterator it1 = s1.begin();
    	while (it1 != s1.end())
    	{
    		(*it1)++;
    		cout << *it1 << " ";
    		++it1;
    	}
    	cout << endl;
    
    	//范围for: 自动迭代,自动判断结束。底层其实就是迭代器
    	//下方为使用范围for依次取s1中的每个字符并赋值给ch,再将ch自增1,最后输出
    	for (auto& ch : s1)
    	{
    		ch++;
    		cout << ch << " ";
    	}
    	cout << endl;
    
    	cout << s1 << endl;
    
    
    	cout << "s2 test" << endl;
    
    	string s2("snow dragon");
    	cout << s2 << endl;
    	string::reverse_iterator rit2 = s2.rbegin();
    	while (rit2 != s2.rend())
    	{
    		cout << *rit2 << " ";
    		++rit2;
    	}
    	cout << endl;
    
    
    	cout << "s3 test" << endl;
    
    	const string& s3("snow dragon");
    	cout << s3 << endl;
    	//string::const_iterator it3 = s3.begin();
    	auto it3 = s3.begin();
    	while (it3 != s3.end())
    	{
    		//*it3 = 'x';
    		cout << *it3 << " ";
    		++it3;
    	}
    	cout << endl;
    
    
    	cout << "s3 reverse iterator test" << endl;
    
    	//auto rit3 = s3.rbegin();
    	string::const_reverse_iterator rit3 = s3.rbegin();
    	while (rit3 != s3.rend())
    	{
    		cout << *rit3 << " ";
    		++rit3;
    	}
    	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
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    4、运行结果

    在这里插入图片描述

    5、总结

    • string和vector都不喜欢用iterator,因为[]更好用,而list、map和set等等只能用迭代器进行访问。
    • iterator是所有容器通用的访问方式,即所有容器的用法都是类似的。
    • iterator的用法像指针一样,它的底层实现有可能就是用指针实现的,也有可能不是,具体要看容器本身。

    八、增加字符的函数

    1、类型

    在这里插入图片描述

    2、作用

    • push_back是在string对象字符串的末尾添加一个字符。
    • append是在string对象字符串的末尾添加一个字符串。
    • +=运算符是在string对象字符串的末尾添加一个字符或字符串。
    • 它们三个将改变字符串的实际大小size和容量空间,如果string对象字符串的容量空间不足,它们会自动对string对象字符串进行增容。

    3、测试代码

    void Test4()
    {
    	string s("snow");
    	s.push_back('-');
    	s.push_back('-');
    	s.append("dragon");
    	cout << s << endl;
    
    	string str("coming");
    	s += '@';
    	s += str;
    	s += "!!!";
    	cout << s << endl;
    
    	s.append(++str.begin(), --str.end());
    	cout << s << endl;
    
    	string copy1(++s.begin(), --s.end());
    	cout << copy1 << endl;
    
    	string copy2(s.begin() + 5, s.end() - 5);
    	cout << copy2 << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    4、运行结果

    在这里插入图片描述

    5、总结

    • 在string尾部追加字符时,s.push_back( c ) / s.append(1, c) / s += 'c’三种实现方式是差不多的。
    • 一般情况下string类的+=操作用的比较多,因为它不仅可以连接单个字符,还可以连接字符串。

    九、c_str

    1、类型

    在这里插入图片描述

    2、作用

    c_str将调用它的string对象字符串转换为一个字符数组,该数组是以\0结尾的,最后返回指向这个数组的指针。

    3、测试代码

    void Test5()
    {
    	string name("snow");
    	cout << name << endl;
    	cout << name.c_str() << endl;
    
    	name += '\0';
    	name += "dragon";
    	cout << name << endl;
    	cout << name.c_str() << endl;
    
    	cout << name.size() << endl;
    	string copy = name;
    	cout << copy << endl;
    
    	cout << '\0' << endl;
    	cout << "end" << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    4、运行结果

    在这里插入图片描述

    5、总结

    • string对象字符串的大小是由它的实际大小size决定的,当输出时,将输出到下标为size - 1时才结束,因为下标为size处的值为\0。
    • 当输出string对象时,\0默认是不输出的。
    • 常量字符串对象或用string对象转换为C类型的字符串时,字符串的结束标志是\0。

    十、搜寻与截取

    1、类型

    在这里插入图片描述

    2、作用

    • find是在字符串中搜索其第一个形参,如果在string对象(字符串)中找到了,则返回开始匹配处的下标;当形参pos指定时,find只搜索字符串下标位置pos处和它之后的字符,pos之前的字符不搜寻;当搜索多个字符时,即find的第一个形参是个字符串时,在string对象中搜寻的序列需要和该形参整个序列都匹配才行。
    • rfind与find类似,只是它从字符串的尾部开始搜寻,pos指定时和find的搜寻顺序相反。
    • substr在调用它的对象的字符串中,从pos位置开始,截取len个字符,然后用截取到的字符序列创建一个string对象并将其返回。
    • npos是一个静态成员常量值,是类型size_t的最大值。当它在字符串的成员函数中用作len(或 sublen)参数的值时,表示直到字符串结束为止。当它作为返回值时,通常用于表示没有找到匹配项。

    3、测试代码

    void DealUrl(const string& url)
    {
    	size_t pos1 = url.find("://");
    	if (pos1 == string::npos)
    	{
    		cout << "非法url" << endl;
    		return;
    	}
    	
    	string protocol = url.substr(0, pos1);
    	cout << protocol << endl;
    
    	size_t pos2 = url.find('/', pos1 + 3);
    	if (pos2 == string::npos)
    	{
    		cout << "非法url" << endl;
    		return;
    	}
    	string domain = url.substr(pos1 + 3, pos2 - pos1 - 3);
    	cout << domain << endl;
    
    	string uri = url.substr(pos2 + 1);
    	cout << uri << endl;
    }
    
    void Test6()
    {
    	string name("snow.dragon.happy.everyday");
    	
    	//输出前缀
    	size_t pos = name.find('.');
    	if (pos != string::npos)
    	{
    		string suff = name.substr(0, pos);
    		cout << suff << endl;
    	}
    
    	//输出后缀
    	pos = name.rfind('.');
    	if (pos != string::npos)
    	{
    		string suff = name.substr(pos);
    		cout << suff << endl;
    	}
    
    	string url1 = "https://legacy.cplusplus.com/reference/string/string/find/";
    	cout << url1 << endl;
    	DealUrl(url1);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    4、运行结果

    在这里插入图片描述

    本文到这里就结束了,如有错误或者不清楚的地方欢迎评论或者私信
    创作不易,如果觉得博主写得不错,请务必点赞、收藏加关注💕💕💕

  • 相关阅读:
    C++ 返回值优化及移动语义
    js array数组json去重
    《动手学深度学习 Pytorch版》 5.1 层和块
    SpringMVC—笔记总结
    kibana配置文件中明文密码加密
    【重温基础算法】内部排序之冒泡排序法
    线程安全的使用ArrayList和HashMap
    【Linux】Linux下静态库(.a)和动态库(.so)的制作和使用
    PyTorch主要组成模块 | hook函数 | 正则化weight decay与Dropout | 标准化
    InstallAnywhere制作安装包
  • 原文地址:https://blog.csdn.net/Snow_Dragon_L/article/details/132695471