目录
1. string类的优势
2. string类的常用接口
2.1 常用构造
1. 空串构造:string();
2. C串构造:string(const char* s);
3. 拷贝构造:string(const string& str);
4. 字符填充构造:string(size_t n, char c);
5. 迭代器构造:string(InputIterator first, InputIterator last);
2.2 string容量操作
1. size_t size(),size_t length()
2. size_t capacity() const
3. bool empty() const
4. void clear()
5. void reserve(size_t n = 0)
6. void resize(size_t n), void resize(size_t char c)
2.3 类对象的访问
1. char& operator[](size_t pos),const char& operator[](size_t pos) const
2. begin()、end()
3. rbegin()、rend()
2.4 string对象处理函数
1. push_back()
2. append()
3. operator+=
4. c_str()
5. insert()
6. erase()
7. find()、rfind()
8. substr()
9. getline()
1. string类的优势
STL(Standard Template Library)库中的string类是一个字符串类,它提供了管理字符串的各种方法和功能。它是一个可变长度的字符序列,可以自动调整自身大小以适应字符串的长度变化。
在之前我们操作字符串都是通过自己去实现相关的函数来进行操作,而且稍不留神就会内存泄漏,在C++中我们更倾向于使用string类来完成和字符串相关的操作。
使用string类相比于使用C语言的字符串有以下优点:
-
更加安全:C语言的字符串没有自带长度信息,容易造成内存越界等安全问题。而string类包含有字符串长度信息,能够避免这类问题。
-
更加方便:C语言中处理字符串需要使用一系列函数,如strlen、strcmp、strcat等等,使用起来比较繁琐。而string类提供了一系列方法,如length、compare、append等等,使用起来更加直观方便。
-
更加灵活:string类可以动态地改变字符串的长度,而C语言的字符串长度通常是固定的。
-
更加高效:string类内部实现了很多优化,如字符串复制采用了引用计数和写时复制等技术,因此性能相对于C语言的字符串更高。
2. string类的常用接口
2.1 常用构造
C++98中支持7种构造函数 ,如下:
- default (1) string();
- copy(2) string(const string& str);
- substring(3) string(const string& str, size_t pos, size_t len = npos);
- from c - string(4) string(const char* s);
- from sequence(5) string(const char* s, size_t n);
- fill(6) string(size_t n, char c);
- range(7) template <class InputIterator> string(InputIterator first, InputIterator last);
但是我们只对其中的五个进行讲解:
1. 空串构造:string();
这个构造函数会构造一个空字符串,长度为0个字符,但是容量不一定为零,比如在vs下空string对象的容量是15,不同环境可能有所不同,主要为了避免频繁的扩容操作。
#include<iostream>
#include<string>
using namespace std;
int main()
{string s1; //创建一个空字符串cout << s1 << endl;cout << s1.capacity() << endl;
}
输出:
2. C串构造:string(const char* s);
以null结尾的字符序列(C串)构造string对象。
int main()
{string s1("hello world!");cout << s1 << endl;}
输出:
3. 拷贝构造:string(const string& str);
利用一个已经存在的string对象构造对象。
int main()
{string s1("hello world!");cout << s1 << endl;string s2(s1);cout << s2 << endl;
}
输出:
4. 字符填充构造:string(size_t n, char c);
利用n个字符构造string对象。
int main()
{string s1(5, 'c');cout << s1 << endl;
}
输出:
5. 迭代器构造:template <class InputIterator> string(InputIterator first, InputIterator last);
使用迭代器区间来构造string对象。
int main()
{string s1(5, 'c');cout << s1 << endl;string s2(s1.begin(), s1.end());cout << s2 << endl;
}
输出:
2.2 string容量操作
1. size_t size(),size_t length()
size()和length()都是返回字符串的有效字符长度,俩个函数的实现原理也完全相同,引入size()是为了和其他容器的接口保持一致。
int main()
{string s1(5, 'c');cout << s1.length() << endl;cout << s1.size() << endl;
}
输出:
2. size_t capacity() const
capacity()是返回空间的总大小,在vs下对象的初始容量是15,当存储的对象超过这个大小的时候才会去开空间,在新开的空间存储数据。
int main()
{string s1(5, 'c');cout << s1.capacity() << endl;string s2(16, 'c');cout << s2.capacity() << endl;
}
输出:
3. bool empty() const
检测字符串是否是空串,是返回true,不是返回false。
int main()
{string s1(5, 'c');if (s1.empty()){cout << "true" << endl;cout << "空" << endl;}else{cout << "false" << endl;cout << "非空" << endl;}
}
输出:
4. void clear()
清空对像中的有效字符。
int main()
{string s1("hello world!");cout << s1 << endl;cout << "--------------------------------" << endl;s1.clear();cout << s1 << endl;
}
输出:
5. void reserve(size_t n = 0)
reserve()是为了给对象预留空间,如果我们提前得知字符串需要的空间我们就可以提前开好,避免频繁扩容带来的性能消耗。当reserve的参数小于string底层空间大小的时候,reserve就不会对容量进行处理。(一般为了保障程序的安全性,reserve()会多开出一部分空间)。
int main()
{string s1(10,'x');s1.reserve(20);cout << s1.capacity() << endl;s1.reserve(2);cout << s1.capacity() << endl;
}
输出:
6. void resize(size_t n), void resize(size_t char c)
修改字符有效个数为n,多出的空间用字符c填充。如果n小于有效字符数,本质就是删字符操作。如果容量不够会扩容。
int main()
{string s1(10, 'x');cout << s1 << endl;s1.resize(20, 'c');cout << s1 << endl;s1.resize(2);cout << s1 << endl;
}
输出:
2.3 类对象的访问
1. char& operator[](size_t pos),const char& operator[](size_t pos) const
返回pos位的字符,并且可以对非const对象进行修改。
int main()
{string s1(10, '1');cout << s1 << endl;s1[4] = '0';cout << s1 << endl;for (int i = 0; i < 10; i++){cout << s1[i] << ' ';}
}
输出:
2. begin()、end()
begin()返回第一个字符位置的迭代器,end()返回最后一个字符的下一个位置的迭代器。begin()和end()都返回了自己的const版本。
int main()
{string s1(10, '1');auto it = s1.begin();for (; it < s1.end(); it++){cout << *it;}
}
输出:
3. rbegin()、rend()
rbegin()获取一个反向迭代器,指向其反向开头,rend()获取一个反向迭代器,指向其反向结尾的前一个理论元素。
int main()
{string s1("123456789");cout << s1 << endl;auto it = s1.rbegin();for (; it < s1.rend(); it++){cout << *it;}
}
输出:
2.4 string对象处理函数
1. push_back()
在字符串后尾插字符c。
int main()
{string s1;s1.push_back('1');cout << s1;
}
输出:
2. append()
append()函数在在C++98有六种重载形式,用于在字符串后追加一个字符串。
- string(1) string& append(const string& str);
- substring(2) string& append(const string& str, size_t subpos, size_t sublen);
- c - string(3) string & append(const char* s);
- buffer(4) string& append(const char* s, size_t n);
- fill(5) string& append(size_t n, char c);
- range(6) template <class InputIterator> string& append(InputIterator first, InputIterator last);
int main()
{string s1("hello");string s2(" world");cout << s1 << endl;s1.append(s2); //在s1结尾追加一个s1cout << s1 << endl;s1.append(s2, 1, 2); //在s1结尾追加s1的下标为1往后的俩个字符cout << s1 << endl;s1.append("C串"); //在s1后追加一个C串cout << s1 << endl;s1.append("123456", 2);//在s1后追加字符串的前 n 个字符。cout << s1 << endl;s1.append(5, 'c'); //在s1后追加5个字符‘c’cout << s1 << endl;string s3("CSDN");s1.append(s3.begin(), s3.end());//在s1后追加一个迭代器区间cout << s1 << endl;
}
输出:
3. operator+=
operator+=()和append()功能类似,都是在字符串后追加内容,但是我们在实际开发中更愿意使用operator+=。
int main()
{string s1("hello ");string s2("world!");s1 += s2;cout << s1 << endl;
}
输出:
4. c_str()
c_str()会返回string对象存储字符串的首地址,用户可以通过这个接口来适配c语言中的某些场景。
int main()
{string s1("hello world!");printf("%s", s1.c_str());
}
输出:
5. insert()
insert()支持在pos位对字符串进行插入操作,但是由于pos位插入涉及到元素的挪动,而挪动元素会使性能下降,所以insert()要少用。insert()有多种重载形式,如下:
- string(1) string& insert(size_t pos, const string& str);
- substring(2) string& insert(size_t pos, const string& str, size_t subpos, size_t sublen);
- c - string(3) string & insert(size_t pos, const char* s);
- buffer(4) string& insert(size_t pos, const char* s, size_t n);
- fill(5) string& insert(size_t pos, size_t n, char c); void insert(iterator p, size_t n, char c);
- single character(6) iterator insert(iterator p, char c);
- range(7) template <class InputIterator> void insert(iterator p, InputIterator first, InputIterator last);
int main()
{string s1("string");cout << s1 << endl;s1.insert(2, "*********");cout << s1 << endl;
}
输出:
6. erase()
erase()是删除字符串的一部分,但是不会改变string对象的容量,如果给的删除字符个数大于pos位后的字符个数,会将后面的全部删除。如果没有给pos位,则默认清空字符串。如果不给删除个数则默认是无符号整型npos(-1)即约等于42亿,就会将pos位后面的字符序列全部删除。
- sequence(1) string& erase(size_t pos = 0, size_t len = npos);
- character(2) iterator erase(iterator p);
- range(3) iterator erase(iterator first, iterator last);
int main()
{string s1("1234567890");s1.erase(2, 3);//从pos位2开始依次删除三个字符,即删除"345"cout << s1 << endl;s1.erase(s1.begin() + 5);cout << s1 << endl;//删除迭代器位置的字符s1.erase(s1.begin(), s1.begin() + 2);//删除beigin()位置和后面1位字符cout << s1 << endl;
}
输出:
7. find()、rfind()
find()函数用于查找某字符串中是否包含某个字符或者字符串,会从pos位往后查找,rfind()则是从pos位往前查找。找到后会返回字符首次出现的pos位或者字符串首次出现的pos位。如果没有找到则会返回npos(无符号整型‘-1’)。
- string(1) size_t find(const string& str, size_t pos = 0) const;
- c - string(2) size_t find(const char* s, size_t pos = 0) const;
- buffer(3) size_t find(const char* s, size_t pos, size_t n) const;
- character(4) size_t find(char c, size_t pos = 0) const;
int main()
{string s1("hello world");size_t pos = s1.find("llo", 0);cout << pos << endl;
}
输出:
8. substr()
substr()会获取pos后包括pos位的n个字符并且返回一个string对象,如果没有给获取长度n,则会默认将后面的包括pos位的所有字符全部获取并且返回一个string对象。
- string substr(size_t pos = 0, size_t len = npos) const;
int main()
{string s1("123456789");cout << s1 << endl;string s2(s1.substr(2, 5));cout << s2 << endl;
}
输出:
9. getline()
从 istream 中提取字符并将其存储到 str 中,直到找到分隔字符 delim(或 (2) 的换行符“\n”)。如果在 is 中到达文件末尾或在输入操作期间发生其他错误,则提取也会停止。如果找到分隔符,则将其提取并丢弃(即不存储它,下一个输入操作将在它之后开始)。请注意,调用之前的任何内容都将替换为新提取的序列。每个提取的字符都追加到字符串中,就像调用其成员push_back一样。(不以空格作为分隔符,可以读取空格符)
- (1)istream& getline(istream& is, string& str, char delim);
- (2)istream& getline(istream& is, string& str);