浅浅介绍一下string,若读者老爷有兴趣不妨垂阅!
目录
1.2.5.cbegin、cend、crbegin、crend
1.6.字符串操作(String operations)相关接口
俺上一篇博客最后浅浅介绍了一下STL,其中STL的六大组件之一就是容器。容器大致来说就是现成的数据结构,当俺们编程的时候想要使用栈、队列、二叉树……的模式来管理数据时,可以直接使用现成的STL里面的容器(栈、队列、二叉树……),就不用我们自己先手动实现栈、队列、二叉树……了。
需要明确的是:string严格来说不属于STL的一部分,属于C++标准库,因为string的诞生时间要早于STL。但是string从功能方面上来说我们可以将其归类到STL里面的容器里面。本博客就浅浅介绍一下STL的容器中的string!
string其实是由一个类模板basic_string实例化而来的,在使用string类时,必须包含头文件<string>以及使用命名空间std。俺们可以在这个文档查询头文件<string>。俺们点击这个文档映入眼帘的就是如下头文件<string>文档界面(没有截全屏):
俺们可以看到类模板实例化了四个类,分别是:string、u16string、u32string、wstring。为什么实例化了那么多类呢?这其实跟编码(Unicode)有关系了,有兴趣的读者老爷可以自行去了解。本篇博客是介绍string类的,有关string类的文档我们可以点击string类文档查阅,也可以点击上述界面的string查阅,都可以调出string类文档。若采取点击上述界面的string查询,步骤如下:
点击string过后跳转到string类文档界面(没有截全屏)如下:
那么我们查阅string类文档,首先我们就可以看到string类的来源:类模板basic_string实例化了basic_string<char>类,该类又被typedef成了string。
说了这么多,那么string到底干啥用的呢?简单点说,string类是一个管理char类型字符串的类,string类底层实现大致是一个字符顺序表!!可以这么说,string类是C++字符串,底层存放有C字符串(C语言中,字符串是以'\0'结尾的一些字符的集合)。
那么俺一边参考string类文档一遍介绍string类。由于string类接口(接口也就是string类已经实现好的成员函数或者非成员函数,我们可以直接使用的)众多,俺只是浅浅介绍一部分接口,且只介绍C++98版本的接口,没介绍的接口可以根据文档自行查阅!
1.成员函数接口
string类文档成员函数部分截图如下:
1.1.默认成员函数相关接口
1.1.1.constructor(构造函数)
PS:打开构造函数文档界面有两种办法:
1.点击俺给的链接:constructor 。
2.点击string类文档界面的constructor:
当俺们打开了构造函数文档界面后,如下图(部分截图):
该如何看着个文档呢?其实文档介绍得很清楚的。
我们看C++98的版本,构造函数重载了7个构造函数,这7个构造函数的具体介绍分别见于以下对应标号的内容,如下图:
俺介绍一些常用的构造函数:
1.string()
根据对应构造函数具体介绍:Constructs an empty string, with a length of zero characters.俺们得知这个构造函数的功能是构造空的string类对象,即空字符串。
#include<string>
#include<iostream>
using namespace std;
int main()
{
string S1;
cout << S1 << endl;
return 0;
}
这里string类实例化对象S1并且调用了构造函数string() 。运行结果如下:
PS:string类在非成员函数接口处重载了流插入运算符(<<)和流提取运算符(>>),所以我们可以直接使用,以下不再提示!
2.string (const char* s)
根据对应构造函数具体介绍: Copies the null-terminated character sequence (C-string) pointed by s.俺们知道这个构造函数的功能是用C-string来构造string类对象。
#include<string>
#include<iostream>
using namespace std;
int main()
{
string S1("I love to eat Totoro");
cout << S1 << endl;
return 0;
}
运行结果如下:
3.string (const string& str)
根据拷贝构造函数的定义可知,这是一个拷贝构造函数,根据函数具体介绍:Constructs a copy of str.俺们知道就是用string类对象str构造一个新string类对象。
#include<string>
#include<iostream>
using namespace std;
int main()
{
string S1("I love to eat Totoro");
string S2(S1);
cout << S1 << endl << S2 << endl;
return 0;
}
运行结果如下:
PS:这个拷贝构造函数完成的拷贝是深拷贝!
4.string (const string& str, size_t pos, size_t len = npos)
根据对应构造函数具体介绍:Copies the portion of str that begins at the character position pos and spans len characters (or until the end of str, if either str is too short or if len is string::npos).俺们知道用string类对象str的一部分(字符位置pos开始并跨越len字符的部分)来构造新string类对象。
#include<string>
#include<iostream>
using namespace std;
int main()
{
string S1("Hello Totoro");
string S2(S1,6,6);
cout << S2 << endl;
return 0;
}
从字符位置6的字符'T'开始拷贝6个字符来构造S2,运行结果如下:
PS:字符位置pos是从0开始计算的,例如"Hello Totoro"中的字符'H'的字符位置是0、字符'T'的字符位置是6。
俺们还要注意的是:如果str太短或形参len是缺省值string::npos,则复制到str的末尾。
#include<string>
#include<iostream>
using namespace std;
int main()
{
string S1("Hello Totoro");
string S2(S1,6,100);//从字符位置6的字符'T'开始到字符串结束最多还有6个字符,这里100>6
cout << S2 << endl;
return 0;
}
运行结果如下:
PS:形参len的缺省值string::npos是string类的公共静态成员变量。npos文档截屏如下:
npos的值用十进制表示是4,294,967,295。因为根据如上文档可见:-1,-1在内存中以补码的形式存在是11111111111111111111111111111111,而npos的类型是size_t的,是无符号的,所以在nops看来npos的值是整形的最大值。。
所以说当形参len是缺省值npos时,复制到str的末尾,因为这说明str太短了,str的长度是不可能为4,294,967,295的。
5.string (const char* s, size_t n)
根据对应构造函数具体介绍:Copies the first n characters from the array of characters pointed by s.俺们可知从s指向的字符数组中复制前n个字符来构造新string类对象。
#include<string>
#include<iostream>
using namespace std;
int main()
{
string S1("I love your Totoro", 10);
cout << S1 << endl;
return 0;
}
运行代码如下:
6.string (size_t n, char c)
根据对应构造函数具体介绍:Fills the string with n consecutive copies of character c.俺们知道就是用字符c的n个连续副本来构造新string类对象。
#include<string>
#include<iostream>
using namespace std;
int main()
{
string S1(5, 'A');
cout << S1 << endl;
return 0;
}
运行结果如下:
1.1.2.destructor (析构函数)
PS:打开析构函数文档界面有两种办法:
1.点击俺给的链接:destructor。
2. 点击string类文档界面的destructor:
打开对应函数文档界面的方法以下不再赘述!!!!!
当俺们打开了析构函数文档界面后,如下图:
析构函数没什么好介绍的。string类自己实现的析构函数必然不会出现当对象销毁时申请的资源没有得到释放的问题 ,当string类对象销毁时让编译器自动调用析构函数来清理对象中的资源就好了。。
1.1.3.operator=(赋值运算符重载)
链接:operator=。
当俺们打开了赋值运算符重载文档界面后,如下图:
赋值运算符重载的功能没什么可解释的,就是为string类对象分配一个新值,替换其当前内容。我们看到赋值运算符重载重载了三个函数。简单易懂,举个栗子:
#include<string>
#include<iostream>
using namespace std;
int main()
{
string S1("I"), S2("LOVE"), S3("YOU");//均调用构造函数string (const char* s)
S1 = "aclm";//调用string& operator= (const char* s)
S2 = 'x';//调用string& operator= (char c)
S3 = S1;//调用string& operator= (const string& str)
cout << S1 << endl << S2 << endl << S3 << endl;
return 0;
}
运行结果:
PS:
调用构造函数也可以写成这样子:
#include<string> #include<iostream> using namespace std; int main() { string S1="hello world";//调用构造函数 return 0; }
1.如何区别调用的是构造函数还是赋值运算符重载呢?
我们要看是否有新string对象创建。如果有,那么调用拷贝构造函数;如果没有,那么调用赋值运算符重载!例如上述代码:主函数中第二条语句调用的就是赋值运算符重载,因为S1是已经存在的对象且没有新string对象产生。
2.以上3个赋值运算符重载均完成深拷贝!
1.2.迭代器(Iterators)相关接口
俺对迭代器也不是很熟悉,俺大概介绍一下迭代器哈。迭代器是STL六大组件之一。迭代器是用来访问STL的容器的,对所有容器都适用。
那么迭代器如何使用呢?就拿string类的迭代器来举个栗子:
#include<string>
#include<iostream>
using namespace std;
int main()
{
string S1 = "Wherever you go ";
string::iterator it = S1.begin();
while (it != S1.end())
{
cout << *it;
it++;
}
cout << endl;
return 0;
}
运行结果:
浅介绍一下上面的代码:
1.不同的容器有其不同的迭代器,并且对应的迭代器属于对应容器的类域,比如上面的string类的迭代器,想要使用就必须突破string类类域,所以写成string::iterator。
2.俺用迭代器定义了一个对象it。begin()这个接口返回一个指向字符串第一个字符的迭代器。
end()这个接口返回一个指向字符串最后一个字符下一个位置的迭代器。我们可以画图理解一下:
3. 当it不等于S1.end(),就解引用并输出,再让it取下一个字符的迭代器(it++)。
4.俺们单从上面迭代器的使用来看,感觉迭代器好像指针啊。其实呢,迭代器的底层实现可能是指针,也可能不是指针。如何迭代器底层实现是指针的话,解引用和++操作那是理所当然可以的。那么当迭代器底层不是指针的话,如何能实现解引用和++操作呢?因为别忘了可以重载解引用运算符和++运算符。
俺上面使用的是正向迭代器,其实还有反向迭代器。俺还是举一个栗子看看:
#include<string>
#include<iostream>
using namespace std;
int main()
{
string S1 = "Wherever you go ";
string::reverse_iterator rit = S1.rbegin();
while (rit != S1.rend())