C++STL详解(一)—— sring类
1. string的定义方式
string类实现了多个构造函数的重载,常用的构造函数如下:
string(); //构造一个空字符串 string(const char* s); //复制s所指的字符序列 string(const char* s, size_t n); //复制s所指字符序列的前n个字符 string(size_t n, char c); //生成n个c字符的字符串 string(const string& str); //生成str的复制品 string(const string& str, size_t pos, size_t len = npos); //复制str中从字符位置pos开始并跨越len个字符的部分
使用示例:
string s1; //构造空字符串 string s2("hello string"); //复制"hello string" string s3("hello string", 3); //复制"hello string"的前3个字符 string s4(10, 's'); //生成10个's'字符的字符串 string s5(s2); //生成s2的复制品 string s6(s2, 0, 4); //复制s2中从字符位置0开始并跨越4个字符的部分
2. string的插入
1、使用push_back进行尾插–插入单个字符
append–插入字符串
void push_back (char c); #include <iostream> #include <string> using namespace std; int main() { string s; s.push_back('C'); s.push_back('S'); s.push_back('D'); s.push_back('N'); cout << s << endl; //CSDN s.append("hello"); cout << s << endl; //CSDNhello return 0; }
2、使用insert插入
string& insert (size_t pos, const string& str);
string& insert (size_t pos, const char* s);
iterator insert (iterator p, char c);
#include <iostream> #include <string> using namespace std; int main() { string s("C"); //C //insert(pos, str)在pos位置插入字符串str s.insert(1, "S"); //CS //insert(pos, string)在pos位置插入string对象 string t("D"); s.insert(2, t); //CSD //insert(pos, char)在pos位置插入字符char s.insert(s.end(), 'N'); //CSDN cout << s << endl; //CSDN return 0; }
3.string的拼接
使用append函数完成string的拼接:
string& append (const string& str); string& append (const char* s); string& append (size_t n, char c); #include <iostream> #include <string> using namespace std; int main() { string s1("I"); string s2(" like"); //append(string)完成两个string对象的拼接 s1.append(s2); //I like //append(str)完成string对象和字符串str的拼接 s1.append(" C++"); //I like C++ //append(n, char)将n个字符char拼接到string对象后面 s1.append(3, '!'); //I like C++!!! cout << s1 << endl; //I like C++!!! return 0; }
4.string的删除
1、使用pop_back进行尾删
void pop_back(); #include <iostream> #include <string> using namespace std; int main() { string s("C++"); s.pop_back(); s.pop_back(); cout << s << endl; //C return 0; }
2、使用erase删除
string& erase (size_t pos = 0, size_t len = npos); iterator erase (iterator p); iterator erase (iterator first, iterator last); #include <iostream> #include <string> using namespace std; int main() { string s("I like C++"); //erase(pos, n)删除pos位置开始的n个字符 s.erase(8, 5); //I like C //erase(pos)删除pos位置的字符 s.erase(s.end()-1); //I like //erase(pos1, pos2)删除[pos1pos2)上所有字符 s.erase(s.begin() + 1, s.end()); //I cout << s << endl; //I return 0; }
5.string的查找
1、使用find函数正向搜索第一个匹配项
size_t find (const string& str, size_t pos = 0) const;
size_t find (const char* s, size_t pos = 0) const;
size_t find (char c, size_t pos = 0) const;
#include <iostream> #include <string> using namespace std; int main() { string s1("http://www.cplusplus.com/reference/string/string/find/"); //find(string)正向搜索与string对象所匹配的第一个位置 string s2("www"); size_t pos1 = s1.find(s2); cout << pos1 << endl; //7 //find(str)正向搜索与字符串str所匹配的第一个位置 char str[] = "cplusplus.com"; size_t pos2 = s1.find(str); cout << pos2 << endl; //11 //find(char)正向搜索与字符char所匹配的第一个位置 size_t pos3 = s1.find(':'); cout << pos3 << endl; //4 return 0; }
2、使用rfind函数反向搜索第一个匹配项
size_t rfind (const string& str, size_t pos = npos) const;
size_t rfind (const char* s, size_t pos = npos) const;
size_t rfind (char c, size_t pos = npos) const;
#include <iostream> #include <string> using namespace std; int main() { string s1("http://www.cplusplus.com/reference/string/string/find/"); //rfind(string)反向搜索与string对象所匹配的第一个位置 string s2("string"); size_t pos1 = s1.rfind(s2); cout << pos1 << endl; //42 //rfind(str)反向搜索与字符串str所匹配的第一个位置 char str[] = "reference"; size_t pos2 = s1.rfind(str); cout << pos2 << endl; //25 //rfind(char)反向搜索与字符char所匹配的第一个位置 size_t pos3 = s1.rfind('/'); cout << pos3 << endl; //53 return 0; }
3、find_first_of()函数
size_t find_first_of (const string& str, size_t pos = 0) const;
size_t find_first_of (const char* s, size_t pos = 0) const;
size_t find_first_of (const char* s, size_t pos, size_t n) const;
size_t find_first_of (char c, size_t pos = 0) const;
正向查找在原字符串中第一个与指定字符串(或字符)中的某个字符匹配的字符,返回它的位置。若查找失败,则返回npos。(npos定义为保证大于任何有效下标的值。)
#include<iostream> using namespace std; int main() { string str="abcdefab"; cout<<str.find_first_of('a')<<endl;//第二个参数为0,默认从下标为0开始查找。 cout<<str.find_first_of("hce")<<endl;//待查串hce第一个出现在原串str中的字符是c,返回str中c的下标2,故结果为2。 cout<<str.find_first_of("ab",1)<<endl;//从下标为1开始查,待查串ab第一个出现在原串str中的字符是b,返回b的下标,结果为1。 cout<<str.find_first_of('h')<<endl;//原串没有待查字符h,故查不到,返回npos。 cout<<str.find_first_of("hw")<<endl;//待查子串任一字符在原串中都找不到,故查不到,返回npos。 return 0; } //有效的下标应该在0~len-1范围内。len=str.size();
4、find_last_of()函数
size_t find_last_not_of (const string& str, size_t pos = npos) const;
size_t find_last_not_of (const char* s, size_t pos = npos) const;
size_t find_last_not_of (const char* s, size_t pos, size_t n) const;
size_t find_last_not_of (char c, size_t pos = npos) const;
逆向查找在原字符串中最后一个与指定字符串(或字符)中的某个字符匹配的字符,返回它的位置。若查找失败,则返回npos。(npos定义为保证大于任何有效下标的值。)
#include<iostream> using namespace std; int main() { string str="abcdefab"; cout<<str.find_last_of("wab")<<endl;//原串最后一个字符首先与待查子串的每一个字符一一比较,一旦有相同的就输出原串该字符的下标.。结果为b的下标7。 cout<<str.find_last_of("wab",5)<<endl; //从原串中下标为5开始逆向查找,首先f与待查子串每一字符比较,若有相同的就输出该字符在原串的下标。 //若一个都没有,就依次逆向比较,即e再与待查子串一一比较,直到原串的b与待查子串中的b相同,然后输出该b在原串的下标1。 cout<<str.find_last_of("fab",5)<<endl;//输出f在原串的下标5。 cout<<str.find_last_of("fab",7)<<endl;//输出b在原串的下标7。 cout<<str.find_last_of("hwk")<<endl;//原串没有待查子串的任何字符,故返回npos。 return 0; } //有效的下标应该在0~len-1范围内。len=str.size();
6.string的比较
使用compare函数完成比较:
int compare (const string& str) const;
int compare (size_t pos, size_t len, const string& str) const;
int compare (size_t pos, size_t len, const string& str, size_t subpos, size_t sublen) const;
比较规则:
1、比较字符串中第一个不匹配的字符值较小,或者所有比较字符都匹配,但比较字符串较短,则返回小于0的值。
2、比较字符串中第一个不匹配的字符值较大,或者所有比较字符都匹配,但比较字符串较长,则返回大于0的值。
3、比较的两个字符串相等,则返回0。
#include <iostream> #include <string> using namespace std; int main() { string s1("hello world"); string s2("hello CSDN"); //"hello world"和"hello CSDN"比较 cout << s1.compare(s2) << endl; //1 //"ell"和"hello CSDN"比较 cout << s1.compare(1, 3, s2) << endl; //-1 //"hello"和"hello"比较 cout << s1.compare(0, 4, s2, 0, 4) << endl; //0 return 0; }
注意
:除了支持string类之间进行比较,compare函数还支持string类和字符串进行比较。
7.string的替换
使用replace函数完成string的替换:
string& replace (size_t pos, size_t len, const char* s);
string& replace (size_t pos, size_t len, size_t n, char c);
#include <iostream> #include <string> using namespace std; int main() { string s("hello world"); //replace(pos, len, str)将pos位置开始的len个字符替换为字符串str s.replace(6, 4, "CSDN"); //hello CSDNd //replace(pos, len, n, char)将pos位置开始的len个字符替换为n个字符char s.replace(10, 1, 3, '!'); //hello CSDN!!! cout << s << endl; return 0; } #include <iostream>
但一般不使用repalce,因为要挪动数据,时间复杂度较高,而是通过空间换时间,比如下面这道题:
8.string的交换
使用swap函数完成两个string类的交换:
void swap (string& x, string& y);
void swap (string& str);
#include <iostream> #include <string> using namespace std; int main() { string s1("hello"); string s2("CSDN"); //使用string类的成员函数swap交换s1和s2 s1.swap(s2); cout << s1 << endl; //CSDN cout << s2 << endl; //hello //使用非成员函数swap交换s1和s2 swap(s1, s2); cout << s1 << endl; //hello cout << s2 << endl; //CSDN return 0; }
9.string的大小和容量
1、使用size函数或length函数获取当前有效字符的个数
size_t size() const;
size_t length() const;
#include <iostream> #include <string> using namespace std; int main() { string s("CSDN"); cout << s.size() << endl; //4 cout << s.length() << endl; //4 return 0; }
2、使用max_size函数获取string对象对多可包含的字符数
size_t max_size() const;
#include <iostream> #include <string> using namespace std; int main() { string s("CSDN"); cout << s.max_size() << endl; //4294967294 return 0; }
3、使用capacity函数获取当前对象所分配的存储空间的大小
size_t capacity() const;
#include <iostream> #include <string> using namespace std; int main() { string s("CSDN"); cout << s.capacity() << endl; //15 return 0; }
4、使用resize改变当前对象的有效字符的个数
void resize (size_t n);
void resize (size_t n, char c);
resize规则:
1、当n大于对象当前的size时,将size扩大到n,扩大的字符为c,若c未给出,则默认为’\0’。
2、当n小于对象当前的size时,将size缩小到n。
#include <iostream> #include <string> using namespace std; int main() { string s1("CSDN"); //resize(n)n大于对象当前的size时,将size扩大到n,扩大的字符默认为'\0' s1.resize(20); cout << s1 << endl; //CSDN cout << s1.size() << endl; //20 cout << s1.capacity() << endl; //31 string s2("CSDN"); //resize(n, char)n大于对象当前的size时,将size扩大到n,扩大的字符为char s2.resize(20, 'x'); cout << s2 << endl; //CSDNxxxxxxxxxxxxxxxx cout << s2.size() << endl; //20 cout << s2.capacity() << endl; //31 string s3("CSDN"); //resize(n)n小于对象当前的size时,将size缩小到n s3.resize(2); cout << s3 << endl; //CS cout << s3.size() << endl; //2 cout << s3.capacity() << endl; //15 return 0; }
注意
:若给出的n大于对象当前的capacity,则capacity也会根据自己的增长规则进行扩大->进行开空间+初始化
5、使用reserve改变当前对象的容量大小
void reserve (size_t n = 0);
reserve规则:
1、当n大于对象当前的capacity时,将capacity扩大到n或大于n。
2、当n小于对象当前的capacity时,什么也不做。
注意:如果使用clear()清理了数据,会缩容,反之不会缩容;但不建议缩容,否则时间换空间(开辟小空间、拷贝、释放之前的大空间)->不值得
#include <iostream> #include <string> using namespace std; int main() { string s("CSDN"); cout << s << endl; //CSDN cout << s.size() << endl; //4 cout << s.capacity() << endl; //15 //reverse(n)当n大于对象当前的capacity时,将当前对象的capacity扩大为n或大于n s.reserve(20); cout << s << endl; //CDSN cout << s.size() << endl; //4 cout << s.capacity() << endl; //31 //reverse(n)当n小于对象当前的capacity时,什么也不做 s.reserve(2); cout << s << endl; //CDSN cout << s.size() << endl; //4 cout << s.capacity() << endl; //31 return 0; }
注意
:此函数对字符串的size没有影响,并且无法更改其内容。只进行开空间->减少消耗,提高效率
6、使用clear删除对象的内容,删除后对象变为空字符串
void clear();
#include <iostream> #include <string> using namespace std; int main() { string s("CSDN"); //clear()删除对象的内容,该对象将变为空字符串 s.clear(); cout << s << endl; //空字符串 return 0; }
7、使用empty判断对象是否为空
bool empty() const;
#include <iostream> #include <string> using namespace std; int main() { string s("CSDN"); cout << s.empty() << endl; //0 //clear()删除对象的内容,该对象将变为空字符串 s.clear(); cout << s.empty() << endl; //1 return 0; }
10.string中元素的访问
1、[ ]+下标
因为string类对[ ]运算符进行了重载,所以我们可以直接使用[ ]+下标访问对象中的元素。并且该重载使用的是引用返回,所以我们可以通过[ ]+下标修改对应位置的元素。
char& operator[] (size_t pos);
const char& operator[] (size_t pos) const;
#include <iostream> #include <string> using namespace std; int main() { string s("CSDN"); //[]+下标访问对象元素 for (size_t i = 0; i < s.size(); i++) { cout << s[i]; } cout << endl; //[]+下标修改对象元素内容 for (size_t i = 0; i < s.size(); i++) { s[i] = 'x'; } cout << s << endl; //xxxx return 0; }
2、使用at访问对象中的元素
因为at函数也是使用的引用返回,所以我们也可以通过at函数修改对应位置的元素。
char& at (size_t pos);
const char& at (size_t pos) const;
#include <iostream> #include <string> using namespace std; int main() { string s("CSDN"); for (size_t i = 0; i < s.size(); i++) { //at(pos)访问pos位置的元素 cout << s.at(i); } cout << endl; for (size_t i = 0; i < s.size(); i++) { //at(pos)访问pos位置的元素,并对其进行修改 s.at(i) = 'x'; } cout << s << endl; //xxxx return 0; }
3、使用范围for访问对象中的元素
需要特别注意的是:若是需要通过范围for修改对象的元素,则用于接收元素的变量e的类型必须是引用类型,否则e只是对象元素的拷贝,对e的修改不会影响到对象的元素。
#include <iostream> #include <string> using namespace std; int main() { string s("CSDN"); //使用范围for访问对象元素 for (auto e : s) { cout << e; } cout << endl; //CSDN //使用范围for访问对象元素,并对其进行修改 for (auto& e : s) //需要修改对象的元素,e必须是引用类型 { e = 'x'; } cout << s << endl; //xxxx return 0; }
其实,范围for的底层就是迭代器
4、使用迭代器访问对象中的元素
#include <iostream> #include <string> using namespace std; int main() { string s("CSDN"); //使用迭代器访问对象元素 string::iterator it1 = s.begin(); while (it1 != s.end()) { cout << *it1; it1++; } cout << endl; //CSDN //使用迭代器访问对象元素,并对其进行修改 string::iterator it2 = s.begin(); while (it2 != s.end()) { *it2 += 1; it2++; } cout << s << endl; //DTEO return 0; }