C++效率掌握之STL库:string函数全解_c++string函数stl
文章目录
- 1.为什么要学习string?什么是string?
- 2.string类对象的常见构造
- 3.string类对象的容量操作
- 4.string类对象的迭代器
- 5.string类对象的元素访问
- 6.string类对象的元素修改
- 7.string类对象的查找、提取、对比
- 8.string类的非成员函数及npos
- 希望读者们多多三连支持
- 小编会继续更新
- 你们的鼓励就是我前进的动力!
从本篇开始将开启C++里的STL库专题,网上有句话说:“不懂STL,不要说你会C++”。STL是C++中的优秀作品,有了它的陪伴,许多底层的数据结构以及算法都不需要自己重新造轮子,站在前人的肩膀上,健步如飞的快速开发
1.为什么要学习string?什么是string?
C语言中,字符串是以’\\0’结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,
不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问
因此创建了string类,比STL库还要早出现,所以有一定的缺陷和冗余

string的主要特征可总结为:
- 字符串是
表示字符序列的类 - 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作
- string在底层实际是:
basic_string模板类的别名
typedef basic_string string - 这个类独立于所使用的编码来处理字节:如果用来处理多字节或变长字符(如UTF-8)的序列,这个类的所有成员(如长度或大小)以及它的迭代器,将仍然
按照字节(而不是实际编码的字符)来操作
2.string类对象的常见构造

string作为一个类也有构造函数,析构函数,=运算符重载,我们重点介绍构造函数里的功能
string()string类对象,即空字符串string (const char* s)C-string来构造string类对象string (const string& str)string (const char* s, size_t n)s 指向的字符数组中复制前 n 个字符string (size_t n, char c)string类对象中包含n个字符cstring (const string& str, size_t pos, size_t len = npos)pos 开始并跨越 len 字符的 str 部分(或者直到 str 的末尾,如果 str 太短或 len 为 string::npos)string (InputIterator first, InputIterator last)💻代码测试示例:
#include #include using namespace std;int main(){string s0(\"Initial string\");string s1;string s2(s0);string s3(s0, 8, 3);string s4(\"Hello\");string s5(\"Best wish!\", 4);string s6a(10, \'x\');string s6b(10, 42); // *的ASCII值是42string s7(s0.begin(), s0.begin() + 7);cout << \"s1: \" << s1 << \"\\ns2: \" << s2 << \"\\ns3: \" << s3;cout << \"\\ns4: \" << s4 << \"\\ns5: \" << s5 << \"\\ns6a: \" << s6a;cout << \"\\ns6b: \" << s6b << \"\\ns7: \" << s7 << \'\\n\';return 0;}
⌨️代码输出示例:

3.string类对象的容量操作

通常在C语言阶段,想要知道字符串的长度,或者对其大小容量进行操作,都要自己手撕函数,不仅耗时还费力,所以string提供了现成的函数
sizelengthmax_sizestring 理论上能够容纳的最大字符数resizen 个,多出的空间用字符 c 或空格填充,少的截断字符串capacityreserveclearstring 对象中存储的所有字符emptytrue ,否则返回 falseshrink_to_fitstring 对象将其容量缩小到和当前字符串长度相匹配的大小🔥值得注意的是:
size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()clear()只是将string中有效字符清空,即大小size缩为0,不改变底层空间大小,即容量capacity不改变resize(size_t n)与resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用空格来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserver不会改变容量大小
💻代码测试示例:
#include #include using namespace std;int main(){string str(\"Hello World!\");cout << \"size:\" << str.size() << endl;cout << \"lenth:\" << str.length() << endl;cout << \"max_size:\" << str.max_size() << endl;cout << \"capacity:\" << str.capacity() << endl;str.reserve(100);cout << \"reserve:\" << str.capacity() << endl;str.resize(17, \'*\');cout << \"resize:\" << str << endl;str.shrink_to_fit();cout << \"shrink_to_fit:\" << str.capacity() << endl;str.clear();cout << \"clear:\" << str << endl;cout << \"empty:\" << str.empty() << endl;return 0;}
⌨️代码输出示例:

4.string类对象的迭代器

迭代器(Iterator)是一种强大的抽象概念,它提供了一种统一的方式来访问和操作容器(如 string、vector 等)中的元素,简单来说就是提供了另一种遍历修改数据的方法
begin + endbegin 获取开头一个字符 + end 获取最后一个字符下一个位置rbegin + rendrbegin 获取最后一个字符 + end 获取开头一个字符上一个位置cbegin + cendbegin + end 一样,但是常量迭代器只读crbegin + crendrbegin + rend 一样,但是反向常量迭代器只读🔥值得注意的是: 定义开头变量前的类型,可以用 auto 代替自动推导,避免了很长的类型,比如后续学习 map 的迭代器类型是这样的 std::map::iterator ,就很有必要用 auto
💻代码测试示例:
#include #include using namespace std;int main(){string str(\"Hello World!\");string::iterator it1 = str.begin();while (it1 != str.end()){cout << *it1 << \' \';it1++;}cout << endl;string::reverse_iterator it2 = str.rbegin();while (it2 != str.rend()){cout << *it2 << \' \';it2++;}cout << endl;return 0;}
⌨️代码输出示例:

5.string类对象的元素访问

string 的元素访问提供了能够像数组那样自由访问字符串中的数组的函数,极大的提高了字符修改的效率
🔥值得注意的是: at 用于访问指定位置元素的成员函数。与 operator[ ] 不同的是,at 会进行边界检查,如果传入的索引超出容器的有效范围,会抛出 std::out_of_range 异常
operator[ ]atbackfront💻代码测试示例:
#include #include using namespace std;int main(){string str(\"Hello World!\");cout << \"operator[ ]:\" << str[11] << endl;cout << \"at:\" << str.at(10) << endl;cout << \"back:\" << (str.back() = \'~\') << \' \' << str << endl;cout << \"front:\" << (str.front() = \'h\') << \' \' << str << endl;return 0;}
⌨️代码输出示例:

6.string类对象的元素修改

string 还提供了 一系列像修改链表那样能够修改字符串的函数
operator+=strappendstrpush_backcassigninserterasereplaceswapstring 对象的内容pop_backstring 中的最后一个元素🔥值得注意的是:
- 在
string尾部追加字符时,s.push_back(c)/s.append(1, c)/s += \'c\'三种的实现方式差不多,一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串 - 对
string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留好
💻代码测试示例:
#include #include using namespace std;int main(){string str;cout << \"operator+=:\" << (str += \"hello\") << endl;cout << \"append:\" << str.append(\" world\") << endl;str.push_back(\'!\');cout << \"push_back:\" << str << endl;str.assign(\"new word\");cout << \"assign:\" << str << endl;str.insert(8, \"!!!\");cout << \"insert:\" << str << endl;str.erase(8, 3);cout << \"erase:\" << str << endl;str.replace(0, 3, \"fashion\");cout << \"replace:\" << str << endl; string tmp(\"happy day!\");swap(tmp, str);cout << \"swap:\" << str << endl;str.pop_back();cout << \"pop_back:\" << str << endl;return 0;}
⌨️代码输出示例:

7.string类对象的查找、提取、对比

string 也提供了一些查找、提取、对比的函数,分配器(allocator)是标准库中一个重要的组件,它将内存分配和对象构造分离,使得容器的内存管理更加灵活
c_strC 格式字符串dataget_allocatorcopyfindrfindfind_first_offind_last_offind_first_not_offind_last_not_ofsubstrcompare🔥值得注意的是:
c_str()返回的是一个const char*类型的指针,这意味着不能通过该指针修改其所指向的字符串内容- 从
C++11开始,string::data()和string::c_str()的行为基本一致,都会返回一个以\'\\0\'结尾的字符数组指针 - 对于
copy,目标字符数组必须有足够的空间来容纳要复制的字符,并且需要手动添加字符串结束符以形成有效的C风格字符串 find系列没找到就返回npos- 对于
compare,逐个比较,如果当前字符串小于比较对象,返回一个负整数;如果当前字符串等于比较对象,返回0;如果当前字符串大于比较对象,返回一个正整数
💻代码测试示例:
#include #include #include using namespace std;int main(){string str(\"Hello World\");const char* str1 = str.c_str();printf(\"c_str:%s\\n\", str1);const char* str2 = str.data();printf(\"data:%s\\n\", str2);char buffer[10];str.copy(buffer, 5, 0);buffer[5] = \'\\0\';cout << \"copy:\" << buffer << endl;string subStr = \"World\";int pos1 = str.find(subStr);cout << \"find:\" << pos1 << endl;int pos2 = str.rfind(\'h\');cout << \"rfind:\" << pos2 << endl;int pos3 = str.find_first_of(subStr);cout << \"find_first_of:\" << pos3 << endl;int pos4 = str.find_last_of(subStr);cout << \"find_last_of:\" << pos4 << endl;int pos5 = str.find_first_not_of(subStr);cout << \"find_first_not_of:\" << pos5 << endl;int pos6 = str.find_last_not_of(subStr);cout << \"find_last_not_of:\" << pos6 << endl;string Substr = str.substr(0, 5);cout << \"substr:\" << Substr << endl;cout << \"compare:\" << str.compare(subStr);return 0;}
⌨️代码输出示例:

8.string类的非成员函数及npos

正是有了非成员函数,才能实现大小交换、自定义交换、输出输入等操作,npos 也提供了一种特殊表达方式
nposoperator+relational operatorsswapstring 对象的内容operator>>operator<<getline🔥值得注意的是:
npos值为-1,被定义为size_t类型的最大值。-1原码为1000 ... 0001,补码则为1111 ... 1111,但赋给size_t时,符号位就用不了了,所以整个补码就为size_t能表示的最大值表示查找操作失败或者某个位置不存在string中operator+尽量少用,因为传值返回,导致效率低- 当使用
>>读取字符串时,它会在遇到空白字符(如空格、制表符、换行符等)时停止读取;getline函数会读取输入流中的一行文本,直到遇到换行符为止,也就是遇到空格不会停止
💻代码测试示例:
#include #include using namespace std;int main(){string str1(\"Hello \");string str2(\"World\");cout << \"npos:\" << str1.npos << endl;cout << \"operator+:\" << (str1 + str2) << endl;cout << \"relational operators:\" << (str1 < str2) << endl;swap(str1, str2);cout << \"swap:\" << str1 << \" \" << str2 << endl;return 0;}
⌨️代码输出示例:

希望读者们多多三连支持
小编会继续更新
你们的鼓励就是我前进的动力!



