【C++】String类:标准库介绍

目录

一.预备知识

1.auto关键字

2.范围for

3.迭代器

二.标准库里的string

1.string类的基本介绍

2.构造函数

​编辑

3.访问及遍历操作

3.1 operator []

3.2 基于范围for 

3.3 使用迭代器

4.迭代器

5.容量操作

 5.1 size和length

5.2 capacity

5.3 reserve和resize 

6.修改操作 

6.1 operator+= 和 append

 6.2 insert

6.3 erase

​编辑

7.查找操作

7.1 find

7.2 rfind

7.3 substr


一.预备知识

1.auto关键字

在C++11中,标准委员会赋予了auto全新的含义:作为一个类型指示符来指示编译器在编译时期推导变量的类型。这使得代码更简洁,尤其是在处理复杂的类型时。

用法示例:

        

1.声明普通变量

auto x = 1; // x 的类型被推断为 int
auto y = 1.11; // y 的类型被推断为 double

2.声明指针变量

int i = 10;
auto p = &i; // p 的类型被推断为 int*
auto* q = &i; // q 的类型同样被推断为 int*

3.声明引用类型

int j = 20;
auto& r = j; // r 的类型被推断为 int&

4.在同一行声明多个变量

auto x1 = 1, x2 = 2; // 正确,x1 和 x2 的类型都推断为 int
auto y1 = 1, y2 = 3.14; // 错误,y1 和 y2 的类型不同

5.auto不能直接声明未初始化变量(需要初始值设定)

6.auto不能作为函数的参数

// 错误用法
void func(auto n) 
{
    // ...
}

7.auto不能直接声明数组

// 错误用法
auto arr[5]; // 错误,无法推断数组类型

auto常在范围for中使用,接下来就介绍范围for 

2.范围for

对于一个有范围的集合而言,由程序员还说明循环的范围是多余的,有时候还容易犯错误。因此C++11中引入了基于范围的for循环。for循环后的括号由冒号:分为两部分,冒号前是用于迭代的变量,冒号后是被迭代的范围,自动迭代,自动取数据,自动判断结束。

范围for可以作用到数组和容器对象(array、string、vector、list...)上进行遍历

int main()
{
	int array[] = { 1, 2, 3, 4, 5 };
 
    //遍历数组每一个值,都乘以2,结果为 2,4,6,8,10
    //自动识别类型,用引用能改变原值
	for (auto& e : array)
		e *= 2;

    //范围for遍历数组array并打印
	for (auto e : array)
		cout << e << ' ';
	cout << endl;


    //范围for遍历字符串str并打印
	string str("hello world");
	for (auto ch : str)
	{
		cout << ch << ' ';
	}
	cout << endl;

	return 0;
}

范围for的底层很简单,容器的遍历实际上就是替换为迭代器,接下来就介绍迭代器 

3.迭代器

迭代器是一种数据类型,在C++中,迭代器实际上是一种对象,它被设计用于在容器中进行元素的遍历和访问。迭代器为程序员提供了一种抽象的方式来访问容器的内容,而不用关心容器的底层实现细节。

例如以下用法,目前还没正式讲到,可以看作一个指针来进行理解:其中string::iterator就是string类的迭代器类型,it是迭代器的变量名,将其看作指针,begin就是开头处,end就是结尾处,*it就是解引用该指针指向的内容,it++使得指针指向下一个内容,如此,大概就是迭代器的遍历操作

int main()
{
	string s1 = "abcde";

	string::iterator it = s1.begin();
	while (it != s1.end())
	{
		cout << *it << " ";
		it++;
	}
	return 0;
}

在string类的标准库和模拟实现中,会具体介绍并进行模拟实现,加深印象。

二.标准库里的string

1.string类的基本介绍

在C语言中,字符串是以'\0'结尾的字符数组,需要手动管理内存和处理字符串操作。在头文件string.h中提供了一系列库函数,如strlen、strcpy、strcat等来对字符串进行操作。但这些函数和字符串是分离的,需要手动管理内存,容易出现越界访问等问题。

因此,在C++标准库中,提供了string类,它封装了字符串操作,提供了丰富的成员函数和运算符重载,使得字符串的操作更加方便和安全。

实际上string类是C++标准库的一部分,学习标准库,是一定需要去读文档的,本文依照该string类的文档介绍进行:string - C++ Reference (plusplus.com)

string在底层实际是basic_string这个模板类使用char类型实例化得到的一个具体类,当然我们在使用时直接使用string即可,它本身就是basic_string<char>

2.构造函数

string作为一个类,构造函数是必不可少的,常用的如下几个:

构造函数名称功能说明
string()默认构造函数,构造空的string类对象,即空字符串
string(const string& s)拷贝构造函数
string(const char* s)用C-string(C风格的字符串)来构造
string(size_t n, char c)string类对象中包含n个字符c
#include<iostream>
using namespace std;
int main()
{
	string s1;
	string s2("abcdefg");
	string s3(10, 'a');
	string s4(s2);
	cout << s1 << endl;
	cout << s2 << endl;
	cout << s3 << endl;
	cout << s4 << endl;
	return 0;
}

3.访问及遍历操作

3.1 operator []

重载下标操作符[ ],使得可以像访问数组一样使用下标来访问字符串中的某个字符,同时返回值是char&,这意味着我们还可以对该下标的字符进行修改等操作。

int main()
{
	string s1 = "abcde";

    //进行遍历,遍历方式类似于数组
	for (int i = 0; i < s1.size(); ++i)
	{
		cout << s1[i] << " ";
	}
	cout << endl;

	//对下标为0的字符(即第一个字符)进行更改
	s1[0] = '0';
	cout << s1;

	return 0;
}

3.2 基于范围for 

int main()
{
	string s1 = "abcde";

    //只能遍历
	for (auto e: s1)
	{
		cout << e << " ";
	}
	cout << endl;

    //若要进行更改,加&引用
	for (auto& e : s1)
	{
		e = 'a';
		cout << e << " ";
	}
	cout << endl;

	return 0;
}

3.3 使用迭代器

在遍历的实现中,更推荐使用迭代器,因为迭代器是大多数数据结构都拥有的,而[ ]不是都有的,使用[ ] 要求物理底层是连续的,如数组等。

int main()
{
	string s1 = "abcde";
	string::iterator it = s1.begin();
	while (it != s1.end())
	{
		cout << *it << " ";
		it++;
	}

	return 0;
}

4.迭代器

迭代器是一种数据结构,在C++中,迭代器是一种对象,它被设计用于在容器中进行元素的遍历和访问。迭代器为程序员提供了一种抽象的方式来访问容器中的元素,而不用关心容器的底层实现细节。

 在string类中就有这四个比较重要的迭代器:

迭代器名称功能说明
begin()返回一个指向字符串中第一个字符的迭代器
end()返回一个指向字符串中最后一个字符的下一个位置的迭代器
rbegin()反向,返回一个指向字符串中最后一个字符的迭代器
rend()反向,返回一个指向字符串中第一个字符的前一个位置的迭代器

string类提供了很多类型的迭代器,包括正向迭代器(iterator)、常量正向迭代器(const_iterator)、反向迭代器(reverse_iterator)、常量反向迭代器(const_reverse_iterator)

  1.  正向迭代器(iterator):用于遍历可修改字符串的迭代器,可以通过begin()、end()方法来获取范围
  2. 常量正向迭代器(const_iterator):用于遍历不可修改的常量对象的迭代器,也可以通过begin()、end()方法获取范围
  3. 反向迭代器(reverse_iterator):用于反向遍历可修改的字符串的迭代器,可以通过rbegin()、rend()方法来获取范围
  4. 反向常量正向迭代器(const_reverse_iterator):用于反向遍历不可修改的常量对象的迭代器,也可以通过rbegin()、rend()方法获取范围

根据begin()的定义,可以发现这其实是一个重载,一个适用于非常量对象,一个适用于常量对象,返回的迭代器也因此不同,例如可以这样使用:

int main()
{
	string s = "abcde";
	const string cs = "abc";
    
    //会取寻找最合适的,此时非常量对象两者都可以,不过使用普通迭代器最合适
	string::iterator it = s.begin();

    //但是权限不能放大,只能缩小
    //不能使用普通迭代器去接收常量字符串的迭代器
    //因此用string::iterator cit = cs.begin()会报错
    //应该使用常量迭代器
	string::const_iterator cit = cs.begin();

	return 0;
}

其他的end();rbegin();rend()都是同理,此处不再赘述。

5.容量操作

函数名称功能说明
size()返回字符串有效字符长度(容器通用)
length()返回字符串有效字符长度(字符串专属)
capacity()返回当前分配给字符串的总空间大小
empty()检测字符串是否为空字符串
clear()清空字符串有效内容
reserve()为字符串预留空间
resize()将有效字符的个数改为n个,多出的空间用字符c填充

 5.1 size和length

两者的作用完全相同:都是返回字符串的有效长度,但是length是只适用于字符串string类的,而size是通用于容器的。

5.2 capacity

capacity()用于返回当前字符串对象分配的储存空间大小(即容量),字符串是存在容量的,这个容量就是指在不重新分配内存的情况下,字符串可以存储的最大字符数。

值得注意的是,capacity()返回的是字符串分配的总空间大小,而不是当前字符串的实际长度,也就是说,capacity()的返回值会大于size()的返回值,因为容量是一定大于等于实际储存的字符长度的,例如:

5.3 reserve和resize 

reserve有保留,预定的意思,功能就是为字符串预留至少n个字符的储存空间,也就是提前分配指定大小空间,好处是节约扩容成本。改变的是容量的大小,而不是实际有效字符的大小。

  • 当n大于当前容量时,reserve就会重新分配内存(可能扩容到n但也可能按其他方式进行扩容到比n大的数目)
  • 若n小于容量,有可能进行缩容也有可能不做处理,这取决于编译器和环境

但有一点是无可置疑的:reserve不会影响到字符串的实际大小与内容,size()的值一定不会变化

resize功能是调整字符串的实际大小为n。根据需要插入或删除字符,使得字符串的实际大小等于n

  • 若n小于当前字符串的实际大小,那么多余的字符将被删除,只剩下前n个字符
  • 若n大于当前字符串的实际大小,那么将用指定的字符c(不指定默认是'\0')来填充新增的部分

6.修改操作 

函数名称功能说明
operator +=在字符串后追加字符串
push_back在字符串后插入字符
append在字符串后追加字符串
insert插入字符(字符串)
erase删除字符

6.1 operator+= 和 append

将+=进行重载,用于将当前字符串与另外一个字符串进行连接,方便快捷,当然append也能做到该功能。

 6.2 insert

常用的两个, 1号是在pos这个下标位置前插入str字符串,2号是在pos下标前插入n个字符c

由于插入需要挪动数据,因此insert的效率其实并不高

6.3 erase

删除从下标pos出开始算起的len的字符,注意这里len的默认值是npos,需要补充说明一下npos

 

npos是C++中的一个静态成员变量,表示无效或不存在的位置。通常用于标识字符串查找等操作未找到匹配项的情况。npos的类型是size_t,值为-1,其补码就是全1,也就是最大的意思。 

7.查找操作

函数名称功能说明
find在字符串中查找指定的字符或子串
rfind在字符串中从右往左查找指定的字符或子串
find_first_of在字符串中从左往右查找指定集合中的任意字符
find_last_of在字符串中从右往左查找指定集合中的任意字符
find_first_not_of在字符串中从左往右查找不在指定集合中的最后一个字符
find_last_not_of在字符串中从右往左查找不在指定集合中的最后一个字符
substr从字符串中提取子串

7.1 find

find用于返回 一个字符或一个字符数组或一个string对象 在string中首次出现的位置,并返回下标,如果找不到就返回npos

7.2 rfind

整体和find类似。不过是从后往前找,找到一个字符或一个字符数组或一个string对象最后一次出现的位置,如果找不到就返回 npos

7.3 substr

从pos位置处开始截取len长度(默认截取到最后),下面以得到文件后缀为例:

int main()
{
	string s1("test.c");
	//得到文件后缀
    
    //从前往后找到第一个.的位置
	size_t pos1 = s1.find('.');
    
    //如果找到了就截取
	if (pos1 != string::npos)
	{
		string ret1 = s1.substr(pos1);
		cout << ret1 << endl;
	}

    
	//如果文件名含有.怎么办
	string s2("te.st.c");

    //使用rfind从后往前查找倒数第一个.
	size_t pos2 = s2.rfind('.');
	if (pos2 != string::npos)
	{
		string ret2 = s2.substr(pos2);
		cout << ret2 << endl;
	}
	return 0;
}

由于string类函数是很丰富的,这里不可能全部一一讲解,更多的需要在使用时去查阅相应的文档即可:<string> - C++ Reference (cplusplus.com)

在下一篇文章中将会具体自己模拟实现string类来加深理解,欢迎持续关注,感谢观看

  • 14
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值