什么是string类?
C++中的string类是一个字符串容器类,它提供了一系列操作字符串的方法,例如连接、查找、删除、替换等。与C语言中的字符串不同,使用string类可以避免许多重复繁琐的操作,使得代码更加简洁和易于维护。另外,string类支持自动内存管理和动态扩容,可以根据需要动态地调整字符串的大小,这也是其与C语言中的字符数组相比的一个优势。
1.字符串是表示字符序列的类
2.标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作单字节字符字符串的设计特性。
3.string类是使用char(即作为它的字符类型,使用它的默认char_traits和分配器类型(关于模板的更多信息,请参阅basic_string)。
4.string类是basic_string模板类的一个实例,它使用char来实例化basic_string模板类,并用char_traits和allocator作为basic_string的默认参数(根于更多的模板信息请参考basic_string)。
5.注意,这个类独立于所使用的编码来处理字节:如果用来处理多字节或变长字符(如UTF-8)的序列,这个类的所有成员(如长度或大小)以及它的迭代器,将仍然按照字节(而不是实际编码的字符)来操作。
总结:
1.string是表示字符串的字符串类
2.该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
3.string在底层实际是:basic_string模板类的别名,typedef basic_string<char, char_traits, allocator>string;
4.不能操作多字节或者变长字符的序列。在使用string类时,必须包含#include头文件以及using namespace std;
我们学习string类需要通过查文档来学习:string类文档介绍
string构造
前面提到了我们学习string类需要结合文档来学习,这里我们在文档中查询string类的构造。
文档下面也对这几个构造函数有解释>
Google翻译>
string();
创建一个空的字符串,长度为零个字符。
eg:
int main() { //构造一个空的字符串 string s1; cout << s1 << endl; return 0; }
可以看到打印出来是空白的。
string (const char* s);
构造一个s字符串的拷贝。
eg:
int main() { //构造一个“hello C++”的字符串 string s0("hello C++"); cout << s0 << endl; return 0; }
string (const string& str);
拷贝构造函数,构造一个str字符串的副本。
eg:
int main() { //构造一个“hello C++”的字符串 string s0("hello C++"); //通过s0字符串拷贝构造出s2 string s2(s0); cout << s0 << endl; cout << s2 << endl; return 0; }
string (const string& str, size_t pos, size_t len = npos);
复制从字符位置pos开始
并跨越len个字符
的str部分(或者直到str的末尾,如果str太短或者len是string::npos)
eg:
int main() { //构造一个“hello World”的字符串 string s0("hello World"); string s3(s0, 8, 3); cout << s0 << endl; cout << s3 << endl; return 0; }
这里我们可以发现这个构造函数中有一个缺省值npos,我们可以查看这个npos的定义:
这里给npos赋值-1,其补码是全1,npos的类型又是size_t(无符号整型)发生了类型转换,把-1强转为size_t类型,所以将-1的补码全1转换为原码,又是无符号类型,所以原反补都相同,此时原码就成为了全1(整型最大值)。
Google翻译>
string (const char* s, size_t n);
这个构造函数的作用是从s字符串中拷贝前n个字符赋给构造的对象。
eg:
int main() { string s5("C++ is very Good!", 12); cout << s5 << endl; return 0; }
string (size_t n, char c);
用字符c的n 个连续拷贝填充字符串。
eg:
int main() { string s6(10, 'c'); cout << s6 << endl; return 0; }
template < class InputIterator >string (InputIterator first, InputIterator last);
范围构造函数
以相同的顺序复制[first,last)范围内的字符序列。
eg:
int main() { string s0("hello C++"); string s7(s0.begin(), s0.begin() + 7); cout << "s0:" << s0 << endl; cout << "s7:" << s7 << endl; return 0; }
string类对象的容量操作
size
size的功能返回字符串的有效长度,以字节为单位。这是符合字符串内容的实际字节数,不一定等于它的存储容量。
eg:
int main() { string str("hello C++!"); cout << str.size() << endl; return 0; }
length
length的功能与size的功能相同,都是返回字符串的有效长度。
eg:
int main() { string str("hello C++!"); cout << str.size() << endl; cout << str.length() << endl; return 0; }
capacity
返回当前为string 分配的存储空间的大小,以字节表示。
容量不一定等于字符串长度。它可以等于或更大,额外的空间允许对象在新字符添加到 string 时优化其操作。
我们在vs2019编译器下编译运行以下代码>
int main() { string str("hello C++!"); cout << str.size() << endl; cout << str.length() << endl; cout << str.capacity() << endl; cout << str.max_size() << endl; return 0; }
可以看到capacity比实际的大小要大一点。
我们再来在g++编译器来运行上面的代码>
我们能看到g++编译器下的capacity和size的大小是相同的,两款编译器下的max_size也是不一样的,所以我们在平时几乎不会用max_size()。(max_size返回的是字符串可达到的最大长度)
empty
测试字符串是否为空
返回字符串是否为空(即它的长度是否为0)
如果字符串长度为0则为true,否则为false。
clear
清除字符串
擦除string 的内容,它变成一个空字符串(长度为0个字符)。
reserve
reserve(size_t n=0):为string预留空间,不改变有效元素个数,当reserve的参数小于
string的底层空间总大小时,reserver不会改变容量大小。
resize
resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。
注意:
- size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()。
- clear()只是将string中有效字符清空,不改变底层空间大小。
string类对象的访问及遍历操作
operator[]
他的功能是可以返回pos位置的字符,也就是说可以通过 [ ]
来访问字符串中的某一个字符。
eg:
int main() { string str("hello C++"); cout << str << endl; for (int i = 0; i < str.size(); i++) { cout << str[i]; } cout << endl; return 0; }
可以看到我们通过str[i]也可以对str字符串进行遍历输出。
他也有函数重载,一个是被const修饰的一个不能被修改,一个没有被const修饰可以进行修改。这里我们举个栗子>
我们对一个字符串的每个字符都进行++处理,再来打印:
int main() { string str("hello C++"); cout << str << endl; //对字符串的每个字符进行++ for (int i = 0; i < str.size(); i++) { str[i]++; } //通过[]对字符串进行遍历 for (int i = 0; i < str.size(); i++) { cout << str[i]; } cout << endl; return 0; }
可以看到我们把原本的字符串进行了修改,当然如果是一个const修饰的对象调用operator[ ],他就会调用const修饰的operator[ ]函数,被const修饰的对象当然也不能被改变。
iterator迭代器
我们来看这样一段代码>
int main() { string s1("hello C+++"); string::iterator it = s1.begin(); while (it != s1.end()) { cout << *it << " "; ++it; } cout << endl; return 0; }
其中s1.begin()
是指向的字符串的第一个字符,s1.end()
指向的是最后一个字符的下一个。
可以看到这个函数的功能是:
将迭代器返回到开头
返回指向字符串第一个字符的迭代器。