目录
承接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关键字
分析
例如以下代码:
#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添加字符带来扩容的麻烦