C++STL—string介绍和使用

C++教学总目录

说明:
针对STL每个类的讲解都会分为:接口介绍和模拟实现。接口介绍是为了让大家学会使用,模拟实现是为了让大家更加了解该类。模拟实现并不是为了造出更好的轮子。
这里推荐一个查看C/C++语法的网站:https://cplusplus.com/
还有一个C++官方的网站:https://cppreference.com/不过我不推荐,因为不好找。
后面对每个类的接口介绍并不需要全部记住,只要记住常用的即可,其他需要用的时候可以查。

string类的接口我会讲的比较详细,后面其他类其实都是类似的,就快速过了。

1、string简介

string是C++中的字符串类型,有了它我们可以更加方便的操作字符串。它的基本结构类似下面:

class string
{
public:
	char* _str;
	size_t _size;
	size_t _capacity;
};

_str是个字符指针,_size代表的是字符串中有效字符个数(不包括\0),_capacity是容量代表当前字符指针所指向空间的大小。
这时候你可能认为string并不是类模板,实际上它是类模板,只不过被typedef重命名了。如下图:
在这里插入图片描述
我们还发现了有其他类型:
在这里插入图片描述
这是因为编码不同,其他类型对应的是其他的编码,string对应的是ASCII编码。这里就不过多赘述,平时我们使用string即可。


2、构造函数

C++98给出了7个构造函数,如下:
在这里插入图片描述
来看看如何使用:

	string s("hello world");
	const char* str = "hello world";
	string s1;     // 无参构造
	string s2(s); // 拷贝构造
	string s3(s, 6);  
	string s4(str); 
	string s5(str, 5); // str的前五个字符
	string s6(10, 'c'); // 用十个字符'c'构造字符串

对每个字符串输出:
在这里插入图片描述

关于构造和拷贝构造就不在赘述了。
第三个构造函数:pos代表从pos位置开始,len表示长度。我们发现这里给了个缺省值npos。那么npos是什么?

在这里插入图片描述
npos是string类内的一个静态const成员变量,实际上是size_t——无符号整型,而无符号的-1就是整数最大值。那么这里长度就是一个非常大的数。
那么意思就是从串s的下标6开始,长度为无限长,也就是到\0为止。所以构造出来的s3就是"world"。
如果是string s3(s, 6, 3); 代表就是从s的下标6开始的3个字符,那么构造出来的串就是"wor"。只要len+pos>=字符串长度,那就是将字符串后面的所有字符拿来构造。

第四个构造函数:用常量字符串来构造,这个很好理解。
第五个构造函数:用常量字符串的n个字符来构造,这里给的是5,那就是用前五个字符来构造,那么构造出来的s5就是"hello"
第六个构造函数:用n个字符c来构造,这里给的是10,‘c’,所以构造出来了10个c的字符串。
第七个构造函数:这里涉及迭代器,暂时不讲。


3、赋值运算符重载

在这里插入图片描述

	string s1("hello world");
	string s2("hello linux");
	string s3("hello c++");
	s1 = s2;
	s2 = "hello java";
	s3 = 'c';

注意:这是赋值运算符重载函数,对象已经被创建出来。


4、迭代器

在这里插入图片描述
上面八个函数都是用来获取迭代器的。迭代器是什么?实际上迭代器是一种类似指针的类型,它可能是指针,也可能不是指针,对于目前我们讲的string类,它的迭代器就是char*的指针,但是对于后面要讲的list(双向循环链表),它的迭代器就不是指针了,而是一个自定义类型。

现在我们要遍历输出string字符串,如下:size()这个函数返回的就是string中的有效字符个数(不包括\0)

	string s = "hello world";
	for (int i = 0; i < s.size(); i++) 
	{
		cout << s[i];
	}

上面是一种写法,我们还可以使用迭代器来写:通过类对象::iterator来获取普通迭代器,begin返回的是第一个数据的位置,end返回的最后一个数据的下一个位置。

在这里插入图片描述


我们前面讲了范围for,前面是用数组来演示,这里我们可以使用对象:

	string s = "hello world";
	for (const auto& e : s)
	{
		cout << e;
	}
	cout << endl;

范围for看似很牛,但实际上范围for的底层是迭代器,因为string支持了迭代器,所以可以使用范围for,如果不支持迭代器,就无法使用范围for了。下面看vs下范围for和迭代器的对比就知道了:
在这里插入图片描述
在这里插入图片描述


上面的是对于普通对象的遍历,如果是const对象呢?——使用const_iterator

	string s = "hello world";
	string::const_iterator cit = s.begin();
	while (cit != s.end())
	{
		cout << *cit;
		++cit;
	}
	cout << endl;

需要注意的是,const_iterator是不能修改值的,而上面的普通迭代器可以修改。


还有反向迭代器reverse_iterator,针对const类型也有const反向迭代器const_reverse_iterator:

在这里插入图片描述


还有另外四个函数:cbegin、cend是用来匹配const_iterator的,crbegin、crend是用来匹配const_reverse_iterator的。但是实际上begin、end和rbegin、rend都有重载,所以可以直接使用begin、end。和rbegin、rend如下图:
在这里插入图片描述
在这里插入图片描述


5、容量相关函数

在这里插入图片描述
前面迭代器用过了,size返回的是有效字符的个数(不包括\0)
length:实际上和size一样,返回字符串长度,这里有些渊源,平时直接使用size就好。
max_size:返回string可以开辟的最大容量,不同平台下不一样,所以没有什么价值。
resize:开空间+初始化。
capacity:获取当前字符串的容量大小。
reserve:修改容量——可以理解为扩容,缩容不明确。
clear:清空字符串所有内容。
empty:判断字符串是否为空。


重点来看resize和reserve:
在这里插入图片描述
在这里插入图片描述

resize是开空间加初始化,reserve是开空间。
resize有两个函数,第一个函数是开至少n的空间,然后后面的空间都初始化为\0,第二个函数是开至少n的空间,并初始化为给定字符c。reserve就是开至少为n的空间。
这里要注意开的空间不同编译器实现不一样,vs下开的空间是大于n的,而g++下测试开的是刚好为n的。所以这里开的空间是大于等于n的。如果给比原来容量小的值是否缩容这个是不一定的,当然一般也不会这么用。

在这里插入图片描述

补充:vs下string的扩容是按1.5倍扩容的,linux下g++编译器是按2倍扩容的。


6、元素访问

在这里插入图片描述

元素访问这里最直白的就是重载了operator[],可以像数组那样使用。back返回最后一个元素,front最开始的元素。

在这里插入图片描述
operator[]支持普通对象和const对象,const对象无法对返回值进行修改。

	string s = "hello world";
	// 像数组一样使用
	cout << s[0] << endl; // h
	s[0] = 'a';           // h->a

在这里插入图片描述
at函数也支持普通对象和const对象,pos是要访问的下表,跟上面差不多:

	string s = "hello world";
	cout << s.at(0) << endl; // h
	s.at(0) = 'a';           // h->a
	s.back();   // 返回'd';
	s.front();  // 返回'a'

7、修改类函数

在这里插入图片描述


在这里插入图片描述
重载了operator+=,这让我们修改字符串会方便,如下:

	string s1 = "hello world";
	string s2 = "hello c++";
	s1 += s2;
	s1 += "hhhhhhh";
	s1 += 't';

在这里插入图片描述

append函数就是在字符串后面添加内容,这里有六个函数,第二个函数类似前面的构造函数,subpos表示开始的下表,sublen表示长度。使用如下:

	string s1 = "hello world";
	string s2 = "hello c++";
	s1.append(s2);               // hello worldhello c++
	s1.append(s2, 6, 3);         // hello worldhello c++c++
	s1.append("hhhhhhhhhhh");    // hello worldhello c++c++hhhhhhhhhhh
	s1.append("xxxxxxxx", 5);    // hello worldhello c++c++hhhhhhhhhhhxxxxx
	s1.append(10, 'y');          // hello worldhello c++c++hhhhhhhhhhhxxxxxyyyyyyyyyy
	s1.append(s2.begin(), s2.end());// hello worldhello c++c++hhhhhhhhhhhxxxxxyyyyyyyyyyhello c++

在这里插入图片描述
这个函数用来在尾部插入一个字符,使用如下:

	string s = "hello world";
	s.push_back('c'); // hello worldc

在这里插入图片描述
这个函数是把字符串清空,替换成新的,使用如下:

	string s1 = "hello world";
	string s2 = "linux";
	s1.assign(s2);		 // linux
	s1.assign(s2, 2, 3); // nux
	s1.assign("dasjk");  // dasjk
	s1.assign("hello linux", 5); // hello
	s1.assign(5, 'x'); // xxxxx
	s1.assign(s2.begin(), s2.end()); // linux

在这里插入图片描述
这个函数是实现在字符串的任意位置插入字符或字符串的。使用如下:

	string s1 = "hello";
	string s2 = "xxx";
	s1.insert(2, s2);				// hexxxllo
	s1.insert(0, s2, 1, 2);			// xxhexxxllo
	s1.insert(0, "axj");			// axjxxhexxxllo
	s1.insert(6, 3, 'y');			// axjxxhyyyexxxllo
	s1.insert(s1.end(), 2, 'z');	// axjxxhyyyexxxllozz
	s1.insert(s1.begin() + 2, 'k'); // axkjxxhyyyexxxllozz
	s1.insert(s1.begin(), s2.begin(), s2.end()); // xxxaxkjxxhyyyexxxllozz

在这里插入图片描述
这个函数是用来删除,使用如下:

	string s = "hello world";
	s.erase(5);							// hello
	s.erase(s.begin());					// ello
	s.erase(s.begin() + 2, s.end());	// el

需要注意的是,给的迭代器区间都是左闭右开的,右边都是指向最后一个元素的下一个位置。


cplusplus网站寄了,之后补充。**加粗样式**
replace函数是用来替换区间中的字符串的,这里就举几个例子:

	string s = "hello world";
	string ss = "hhhh";
	s.replace(0, 5, "linux"); // linux world
	s.replace(1, 4, ss);      // lhhhh world
	s.replace(0, 20, 3, 'x'); // xxx

在这里插入图片描述
swap函数是用来交换两个对象的成员变量的。

在这里插入图片描述
交换后,str1就变成了str2,str2变成了str1.


在这里插入图片描述
这个函数就很好理解了,删除最后一个字符。


8、字符串操作函数

在这里插入图片描述


在这里插入图片描述
这个函数返回c的字符串指针,由于string重载了流插入,所以可以直接用cout输出。也可以用这个函数获取返回值输出:

	string s = "hello";
	// 以下结果相同,但是含义不同。一个是重载了流插入,另一个是字符指针。
	cout << s << endl;  
	cout << s.c_str() << endl;  

当使用cout其实还没有什么作用,但如果用printf输出,这里的c_str函数作用就很大了:

	string s = "hello";
	printf("%s\n", s.c_str());

在这里插入图片描述
find函数用来查找字符串或者字符,找到就返回下标,找不到就返回npos,使用如下:

    string s1 = "hello linux";
    string s2 = "hello";
    int x1 = s1.find(s2, 0);  // 从0下表开始找,找到返回下标
    cout << x1 << endl;  // 输出0
    int x2 = s1.find("linux", 0);
    cout << x2 << endl;  // 输出6

rfind基本上同find,只不过rfind是从后往前找,这里不再赘述。


在这里插入图片描述
substr用来截取字符串,并转换为string对象返回。使用如下:

    string s = "hello linux";
    string ss = s.substr(0, 5);
    cout << ss << endl; // 输出hello

9、非成员函数

在这里插入图片描述
重载了>>运算符,所以可以直接用cin读取。同时重载了<<可以直接cout输出。另外还有一个getline函数,这个getline函数是用来读取一整行的,包括空格和换行。而我们用cin遇到空格和换行就会停止读取。所以如果要读取带有空格的字符串就要使用getline。
getline函数使用如下:

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值