STL容器之string进阶操作

目录

string类对象的访问和遍历操作

1.通过正向迭代器

2.通过反向迭代器

3.范围for

string类对象的容量操作

1.reserve

2.resize

string类对象的查找操作

1.find + npos

2.rfind+npos 

3.substr

 string类对象的插入和删除操作 

1.insert

2.erase


上期我们学习了string类的一些基本操作,本期我们将学习string中的一些进阶操作。

string类对象的访问和遍历操作

1.通过正向迭代器

通过正向迭代器:begin+ end

begin:获取第一个字符的迭代器 

end:获取最后一个字符下一个位置的迭代器

代码如下: 

void stringTest1()
{
	string s1("hello yjd");
	string::iterator it1 = s1.begin();
	while (it1 != s1.end())
	{
		cout << *it1 << " ";
		it1++;
	}
	cout << endl;
	string::iterator it2 = s1.begin();
	while (it2 != s1.end())
	{
	
		cout <<++(*it2) << " ";
		it2++;
	}
}

 结果如下:

我们发现,通过正向迭代器我们可以实现字符串元素的遍历和修改。那么迭代器究竟是什么呢?

 图示如下:

STL容器之string进阶操作_第1张图片

解析:其实我们可以将迭代器类型iterator看成是字符指针类型,begin用来返回字符串中第一个字符的地址,end用来返回字符串中最后一个字符的地址的下一个地址,将返回的字符地址传给了迭代器变量(字符指针),此时迭代器变量自然就可以访问字符数组中的元素。 

2.通过反向迭代器

通过反向迭代器:rbegin + rend

rbegin:获取最后一个一个字符的迭代器 

rend:获取最后一个字符的前一个位置的迭代器

代码如下:

void stringTest2()
{
	string s1("hello yjd");
	string::reverse_iterator it1 = s1.rbegin();
	while (it1 != s1.rend())
	{
		cout << *it1 << "";
		it1++;
	}
}

截图如下:

反向迭代器的使用与正向迭代器是相反的,即逆序访问,但是它们的底层原理还是相同的。   

注意:迭代器除过普通迭代器之外还有常量迭代器,我们在使用时,如果是访问普通字符串对象那么就是用普通迭代器,如果是访问const字符串对象,那么就要使用const迭代器。

3.范围for

范围for: C++11支持更简洁的范围for的新遍历方式

代码如下: 

void stringTest3()
{
	string s1("hello yjd");
	//遍历数组
	for (auto e :s1 )
	{
		cout << e << " ";
	}
	cout << endl;
	//如果想改变字符数组的值,就应该将将传值改为传引用
	for (auto& e : s1)
	{
		cout << ++e<< " ";
	}
}

截图如下:

string类对象的容量操作

1.reserve

reserve:申请空间,但是不进行初始化。

2.resize

resize:为字符串申请空间,并且初始化为字符'\0',也可以用指定的字符进行初始化,如果申请的空间小于原本字符串的长度,则只保留原有字符串的部分元素。

1.代码如下:

string s1("hello yjd");

截图如下:

STL容器之string进阶操作_第2张图片

2.代码如下:

s1.reserve(50);

 截图如下:

STL容器之string进阶操作_第3张图片

我们发现,只是增加了字符串的容量,但是字符串的有效字符的个数是没有变化的。 

3.代码如下:

s1.resize(50);

截图如下:

STL容器之string进阶操作_第4张图片

申请了空间,并且对这些空间进行了初始化,如果没有给定初始值,就默认初始化为'\0'。

4.代码如下

s1.resize(50, 'x');

STL容器之string进阶操作_第5张图片

 申请了空间,并且对这些空间进行了初始化,初始化为了给定的字符。 

 5.代码如下:

s1.resize(5);

截图如下:

STL容器之string进阶操作_第6张图片

我们发现,只要申请的空间小于原有的字符串的有效字符,那么就会让原有字符串的字符个数成为申请的空间的大小。

总结:reserve和resize都用于申请空间都可以改变字符串的容量,reserve申请空间不初始化,所以不改变字符串有效字符的个数,只改变容量capacity,但是resize申请空间时进行了初始化,所以不仅改变了容量capacity,还改变了字符串有效字符的个数。因为字符串是有默认的容量的,如果resize申请的空间小于原有的字符串的长度,那么此时只改变有效字符的个数, 并不改变容量capcity。 

string类对象的查找操作

1.find + npos

find + npos:从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置,没有给定pos位置就从字符串头开始找。

2.rfind+npos 

rfind+npos:从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置,如果没有给定pos位置,就从字符串最后一个元素的位置开始找。

3.substr

substr:在str中从pos位置开始,截取n个字符,然后将其返回,如果没有指定,默认从当前位置往后截取所有元素

注意:这里的nps是string类中的一个静态变量为无符号正型-1,所以也就是一个42亿九千万的一个很大的数,因为一个字符串不可能这么长,所以如果返回的值是-1,就代表这个字符找不到。且因为npos是string类中的静态变量,所以我们在类外进行访问时必须加上类作用域限定符。

情景1:我们设置了一个文件的名称为"file.txt",如何求文件的后缀名呢? 

代码如下:


void stringTest5()
{
	string file("file.txt");
	size_t pos=file.find('.');
	if (pos != string::npos)
	{
		cout << file.substr(pos)<

我们用了两个函数find找到了.的位置,然后从当前位置开始,求出当前位置和当前位置后的所有字符,这些字符组成了文件的后缀。 

截图如下: 

 

情景二.如果一个文件的名称现在为"file.txt.zip",怎样去求这个文件的后缀名称呢?

代码如下:

void stringTest5()
{
	string file("file.txt.zip");
	size_t pos=file.rfind('.');
	if (pos != string::npos)
	{
		cout << file.substr(pos)<

不管一个文件名有多少疑似后缀的后缀,最后一个后缀一定是文件的后缀,所以我们可以从字符串的后面开始找到第一个.,这个.以及这个点之后的字符就组成了这个文件的文件后缀。

截图如下:

 string类对象的插入和删除操作 

1.insert

insert:插入操作

代码如下:

void stringTest6()
{
	string s1 = "hello yjd";
	//头插
	s1.insert(s1.begin(), 'h');
	cout << s1 << endl;
	s1.insert(0, "hello");
	cout << s1 << endl;
	//在头部位置插入两个y
	s1.insert(0, 2, 'y');
	cout << s1 << endl;

	//中间某个位置插入
	string s2 = "hello yjd";
	s2.insert(2, "nihao");
	cout << s2 << endl;

	//尾部插入
	string s3= "hello yjd";
	s3 += 'y';
	cout << s3 << endl;
	s3 += "hahahaha";
	cout << s3 << endl;
}

截图如下:

STL容器之string进阶操作_第7张图片

 注意:我们不支持头插和中间插入字符或者字符串,因为string类本质上就是一个数组,如果我们在头部和中间插入,就会移动整个数组,复杂度太高,消耗太大,所以一般情况下只建议使用尾插。 

2.erase

erase:删除操作

代码如下:

void stringTest7()
{
	string s1("hello yjd");
	//头部删除
	s1.erase(0, 2);
	cout << s1 << endl;

	//中间某一位置删除
	s1.erase(2, 1);
	cout << s1 << endl;
	//尾部删除
	s1.erase(s1.size() - 1, 1);
	cout << s1 << endl;

	//没有给定删除的个数,默认全部删除
	s1.erase(0);
	cout << s1 << endl;
}

截图如下:

STL容器之string进阶操作_第8张图片

注意:我们不建议头删和中间删除,因为头删和中间删除我们同样会移动整个数组,复杂度太高了,所以我们一般只建议尾插。

好了,到了这里string类的所有基本操作和进阶操作我们已经全部学习完成了,下期我们将开始进行string类的模拟实现。

本期内容到此结束^_^

你可能感兴趣的:(知识总结,C++,c++,开发语言)