CD35.【C++ Dev】STL库的string的使用 (中)

目录

1.串联类和对象的知识重新理解

迭代器

知识回顾

end()的提醒

带迭代器的范围for

知识回顾

分析

迭代器的分类

正向迭代器(可以用于正向遍历)

cbegin()和cend()的遍历代码

反向迭代器(可以用于反向遍历)

rbegin()和rend()的指向位置

反向遍历代码示例

size()和length()

max_size()

capacity()

演示动态扩容

clear()


承接CD34.【C++ Dev】STL库的string的使用 (上)文章

1.串联类和对象的知识重新理解

迭代器

任何容器都支持迭代器,且使用方法类似

知识回顾

之前在CC13.【C++ Cont】初识string类字符串的迭代器文章讲过,但讲的比较少,这里讲讲迭代器的其他知识

迭代器即iterator,是像指针一样的类型,它有可能指针,也有可能不是指针

end()的提醒

返回指向字符串最后一个字符的下一个位置(为空)的迭代器

例如以下代码:

#include <string>
using namespace std;
int main()
{
	string str("helloworld");
	string::iterator begin = str.begin();
	string::iterator end = str.end();
	return 0;
}

下断点到return 0,查看监视窗口begin和end的值,发现end里面的ptr指向的是"helloworld"字符串结尾的\0

其实在cplusplus网https://legacy.cplusplus.com/reference/string/string/end/中也提到了:

"follow the last character in the string"即跟在字符串的最后一个字符之后

带迭代器的范围for

知识回顾

CC7.【C++ Cont】范围for的使用和auto关键字

CC7.5【x86汇编】底层分析范围for(非迭代器类)的执行过程

CD8.【C++ Dev】auto、范围for、内联函数和nullptr

分析

例如以下代码:

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string str("helloworld");
	for (char it : str)
	{
		cout << it;
	}
	return 0;
}

从头到尾遍历并打印字符串str,运行结果:

反汇编代码:

发现里面调用的begin()和end()迭代器,结论: 范围for的底层其实替换为迭代器

,因此如果一个类有迭代器就可以用范围for,STL的栈就没有迭代器(先进后出,不支持访问除了栈顶之外的元素) 

★注意:范围for只能用于正向遍历,因为值支持正向迭代器★

迭代器的分类

正向迭代器(可以用于正向遍历)

begin()和end():指向两种类型的string类字符串

 具体要看string类字符串是否被const修饰

C++11: cbegin()和cend():指向不可以修改(只读)的string类字符串(c为const的首字母)

cbegin()和cend()的遍历代码
#include <iostream>
#include <string>
using namespace std;
int main()
{
	const string str("helloworld");
	for (string::const_iterator it = str.cbegin(); it < str.cend(); it++)
		cout << *it;
	return 0;
}

 运行结果:

反向迭代器(可以用于反向遍历)

rbegin()和rend()用于可修改的string类字符串

crbegin()和crend()用于不可修改(只读)的string类字符串

rbegin()和rend(),r是reverse的缩写参考网站:https://legacy.cplusplus.com/reference/string/string/rbegin/

https://legacy.cplusplus.com/reference/string/string/rend/

rbegin()返回指向字符串最后一个字符的反向迭代器

rend()返回指向字符串第一个字符之前的理论元素(这个元素具体是什么并不知道)的反向迭代器

注意到它们两个的返回类型:

如果string字符串能修改,返回reverse_iterator;如果只读,返回const_reverse_iterator

rbegin()和rend()的指向位置

测试以下代码,下断点到return 0,监视窗口查看rb和re的内容:

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string str("helloworld");
	string::reverse_iterator rb = str.rbegin();
	string::reverse_iterator re = str.rend();
	return 0;
}

画图可知:

(re指向的值并不知道,具体和编译器的设置有关)

反向遍历代码示例

string字符串能修改:

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string str("helloworld");
	for (string::reverse_iterator it=str.rbegin() ;it<str.rend();it++)
	{
		cout << *it;
	}
	return 0;
}

运行结果:是倒着打印的

string字符串不能修改:

#include <iostream>
#include <string>
using namespace std;
int main()
{
	const string str("helloworld");//const对象不能使用普通的迭代器,否则导致权限放大
	for (string::const_reverse_iterator it=str.rbegin() ;it<str.rend();it++)
	{
		cout << *it;
	}
	return 0;
}

当然也可以使用crbeign()和crend():

const string str2("helloworld");
for (string::const_reverse_iterator it = str2.crbegin(); it < str2.crend(); it++)
{
	cout << *it;
}

(注:如果str2不是const类型,it也是string::const_reverse_iterator) 

运行结果:是倒着打印的

上方两种的代码中的it前面都可以改成auto,自动推导比较方便

总结:迭代器提供一种统一的方式访问和修改容器中的数据,算法就可以通过迭代器去处理容器中的数据(私有)

size()和length()

这两个成员函数功能一样,都是返回字符串的长度,不含\0

例如string::size - C++ Reference的例子

#include <iostream>
#include <string>
using namespace std;
int main()
{
	std::string str("Test string");
	cout << "The size of str is " << str.size() << " bytes.\n";
	cout << "The length of str is " << str.length() << " bytes.\n";
	return 0;
}

运行结果:

max_size()

https://legacy.cplusplus.com/reference/string/string/max_size/

 返回字符串可以达到的最大长度(返回值和不同操作系统的不同平台的编译器有关,不准确)

VS2022:

Dev C++:

Ubuntu服务器:

capacity()

https://legacy.cplusplus.com/reference/string/string/capacity/

对于同样的string类字符串,不同操作系统的不同平台的编译器capacity()返回的值不尽相同,具体和内存分配策略有关

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string str("Test string");
	cout << str.capacity() << " bytes.\n";
	return 0;
}

VS2022:

 Dev C++:

Ubuntu服务器: 

演示动态扩容

向原string添加150个'a',看看capacity的变化情况

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string str("Test string");
	size_t cap = str.capacity();
	cout << cap <<endl;
	for (int i = 0; i < 150; i++)
	{
		str += 'a';
		if (cap != str.capacity())
		{
			cout << str.capacity() << endl;
			cap = str.capacity();
		}
	}
	return 0;
}

VS2022:

Dev C++:明显的二倍扩容

Ubuntu服务器:

clear()

https://legacy.cplusplus.com/reference/string/string/clear/

清除字符串

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string str("Test string");
	cout << str.size() << endl;
	cout << str.capacity() << endl;
	str.clear();
	cout << str.size() << endl;
	cout << str.capacity() << endl;
	return 0;
}

VS2022:

clear()使size()清零,但没有改变capacity(),这是因为避免可能再次对str添加字符带来扩容的麻烦

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhangcoder

赠人玫瑰手有余香,感谢支持~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值