4. string类对象的容量操作
4.1 string中有效字符个数(size与length)
size与length返回字符串有效字符长度(不包含\0)
前面已经说过,size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()。
代码演示:
int main() { string s1("hello world!"); cout << s1.size() << endl; return 0; }
4.2 string的当前容量(capacity)
capacity返回空间总大小
代码如下:
int main() { string s1("hello world!"); cout << s1.capacity() << endl; return 0; }
设计程序检测string的扩容机制:
int main() { string s1("hello world!"); //检测string的扩容机制 size_t old = s1.capacity(); //令old=原本的容量大小 cout << old << endl; for (size_t i = 0; i < 500; i++) { s1.push_back('l'); //尾插l的过程中string的容量大小一定会发生变化 if (old != s1.capacity()) //当发生扩容时,打印新的string容量大小 { cout << s1.capacity() << endl; old = s1.capacity(); } } return 0; }
4.3 string提前开空间(reserve)
reserve为字符串预留空间(即可以理解为需要多少空间提前开好,不用边用边开)
reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于 string的底层空间总大小时,reserver不会改变容量大小。(在vs2019下reserve只扩容不缩容,在g++下reserve会缩容,但只会缩到现有数据的大小)
用法如下:
int main() { string s1("hello world!"); cout << s1.capacity() << endl; s1.reserve(500); cout << s1.capacity() << endl; return 0; }
4.4 string提前开空间并初始化(resize)
resize将有效字符的个数改变成n个,多出的空间用字符c填充
resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字 符个数增多时:resize(n)用'\0'来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大 小,如果是将元素个数减少,底层空间总大小不变。
①如果要扩容的空间>capacity,则扩容+尾插。验证如下:
int main() { string s1("hello world!"); cout << s1.size() << endl; cout << s1.capacity() << endl; //如果要扩容的空间>capacity s1.resize(100); cout << s1.size() << endl; cout << s1.capacity() << endl; cout << s1 << endl; return 0; }
int main() { string s1("hello world!"); cout << s1.size() << endl; cout << s1.capacity() << endl; //如果要扩容的空间>capacity s1.resize(100, 'x'); cout << s1.size() << endl; cout << s1.capacity() << endl; cout << s1 << endl; return 0; }
②如果size<n<capacity,则只尾插不扩容,验证如下:
int main() { string s1("hello world!"); cout << s1.size() << endl; cout << s1.capacity() << endl; //如果size<n<capacity s1.resize(13,'x'); cout << s1.size() << endl; cout << s1.capacity() << endl; cout << s1 << endl; return 0; }
③如果n<size,只删除、保留前n个,不缩容,验证如下:
int main() { string s1("hello world!"); cout << s1.size() << endl; cout << s1.capacity() << endl; //如果n<capacity s1.resize(6); cout << s1.size() << endl; cout << s1.capacity() << endl; cout << s1 << endl; return 0; }
(reserve与resize的区别可以概括为一句话:reserve只影响容量,不影响数据,resize既影响容量又影响数据)
4.5 清空string所有字符(clear)
清空有效字符
clear()只是将string中有效字符清空,不改变底层空间大小。
验证如下:
int main() { string s1("hello world!"); cout << s1.size() << endl; cout << s1.capacity() << endl; s1.clear(); cout << s1.size() << endl; cout << s1.capacity() << endl; cout << s1 << endl; return 0; }
4.6 判断string是否为空(empty)
检测字符串释放为空串,是返回true,否则返回false(注意:空为真,不空为假)
验证如下:
int main() { string s1("hello world!"); cout << s1.empty() << endl; string s2; cout << s2.empty() << endl; return 0; }
5.string类对象的修改操作
修改操作无非就是增删查改,这里只介绍比较常用的操作
5.1 增
1. append插入
增操作其实已经有了一个我们熟悉的push_back,可是push_back每次只能尾插一个字符,为了方便就有了append:
比如我们二者兼用:
int main() { string s1("hello"); s1.push_back(' '); s1.append("world!"); cout << s1 << endl; return 0; }
append的其他常用用法如下:
①string& append (const char* s);插入常量字符串(上面的用法)
②string& append (const string& str);插入string:
int main() { string s1("hello"); string s2(s1); return 0; }
③string& append (const string& str, size_t subpos, size_t sublen);插入string从subpos位置起到sublen个字符止的那部分:
int main() { string s1("hello world!"); string s2(s1,1,3); return 0; }
④string& append (const char* s, size_t n);插入常量字符串的前n个:
int main() { string s1("hello world!", 3); return 0; }
⑥string& append (size_t n, char c);插入n个字符c:
int main() { string s1(4,'x'); return 0; }
⑦string& append (InputIterator first, InputIterator last);插入string的一部分:
插入s1:
int main() { string s1("hello world!"); string s2; s2.append(s1.begin(), s1.end()); return 0; }
插入去头去尾的s1:
int main() { string s1("hello world!"); string s2; s2.append(++s1.begin(), --s1.end()); return 0; }
2. +=插入
①string& operator+= (const string& str);插入string:
int main() { string s1("hello world!"); string s2; s2 += s1; return 0; }
②string& operator+= (const char* s);插入字符串:
int main() { string s1; s1 += "hello world!"; return 0; }
③string& operator+= (char c);插入字符:
int main() { string s1; s1 += '!'; return 0; }
3.insert指定位置插入
观察push_back与append,二者都是尾插,那有没有不是尾插的方法呢?当然有!
①string& insert (size_t pos, const string& str);在pos位置插入string:
int main() { string s1("hello "); string s2("world!"); s2.insert(0, s1); return 0; }
②string& insert (size_t pos, const string& str, size_t subpos, size_t sublen);在pos位置插入string的一部分:
int main() { string s1("hello "); string s2("world!"); s2.insert(0, s1, 1, 3);//ellworld! return 0; }
③string& insert (size_t pos, const char* s);在pos位置插入字符串:
int main() { string s1("world!"); s1.insert(0, "hello ");//hello world! return 0; }
④string& insert (size_t pos, const char* s, size_t n);在pos位置插入字符串的前n个:
int main() { string s1("world!"); s1.insert(0, "hello ",3);//helworld! return 0; }
5.2 删
1. 尾删(pop_back)
尾删:
int main() { string s1("hello world!"); s1.pop_back();//hello world return 0; }
2. 删除指定位置(erase)
①string& erase (size_t pos = 0, size_t len = npos);从第pos个位置删除len个字符:
int main() { string s1("hello world!"); s1.erase(5, 1);//helloworld! return 0; }
②iterator erase (iterator p);删除string的第p个位置:
int main() { string s1("hello world!"); s1.erase(s1.begin()+1);//hllo world! return 0; }
5.3 查
1.取string子串(substr)
string substr (size_t pos = 0, size_t len = npos) const;从pos位置开始,取len个字符:
int main() { string s1("hello world!"); string s2 = s1.substr(6, 5);//world return 0; }
2.查找指定字符(find)
关于find的返回值:
The position of the first character of the first match.
If no matches were found, the function returns string::npos.
即:如果找到了就返回找到的第一个的下标,如果没有找到就返回整型的最大值。
①size_t find (char c, size_t pos = 0) const;从pos位置开始找c,没有给pos默认从头开始找:
int main() { string s1("hello world!"); size_t pos1 = s1.find('l');//2 size_t pos2 = s1.find('l', 5);//9 size_t pos3 = s1.find('x');//npos return 0; }
例:取string指定的一部分:
int main() { //取文件名后缀 string s1("test.cpp"); size_t pos1 = s1.find('.'); if (pos1 != string::npos) { /*string s2 = s1.substr(pos1, s1.size() - pos1);*/ string s2 = s1.substr(pos1); cout << s2 << endl; } return 0; }
5.4 改
1. 修改string指定位置(replace)
①string& replace (size_t pos, size_t len, const string& str);在pos位置的len个字符替换成str:
int main() { string s1("hello world!"); s1.replace(5, 1, "?");//hello?world! return 0; }
2. string与string交换(swap)
与另一个string交换:
int main() { string s1("hello world!"); string s2; s2.swap(s1);//hello world! return 0; }
5.5 查改结合完成替换操作
例:将s1的空格全部替换为?
方法一:
int main() { string s1("have a good time!"); cout << "替换前s1=" << s1 << endl;//have a good time! size_t pos = s1.find(' ', 0); while (pos != string::npos) { s1.replace(pos, 1, "?"); pos = s1.find(' ', pos + 1); } cout << "替换后s1=" << s1 << endl;//have?a?good?time! return 0; }
实际中replace效率太低,因此尽量少用replace
方法二:
int main() { string s1("have a good time!"); cout << "替换前" << s1 << endl;//have a good time! string s2; for (auto ch : s1) { if (ch == ' ') { s2 += "?"; } else { s2 += ch; } } s1.swap(s2); cout << "替换后" << s1 << endl;//have?a?good?time! return 0; }