目录
前言
前面我们讲了C语言的基础知识,也了解了一些数据结构,并且讲了有关C++的命名空间的一些知识点以及关于C++的缺省参数、函数重载,引用 和 内联函数也认识了什么是类和对象以及怎么去new一个‘对象’,也相信大家都掌握的不错,接下来博主将会带领大家继续学习有关C++比较重要的知识点——STL(string类)。下面话不多说坐稳扶好咱们要开车了😍
一、STL简介
1.STL是什么
C++的Standard Template Library(STL)是C++标准库中一个包含了丰富的模板类和函数的部分,它提供了许多常用的数据结构和算法,以及与之相关的功能组件。STL的设计目标是提供通用、高效和可重用的模板类,以便于开发人员编写高质量的C++代码。
2.STL的内容
STL包含六个主要组件:分别是容器(Containers)、算法(Algorithms)、迭代器(Iterators)、函数对象(Function Objects)、适配器(Adapters)和分配器(Allocators),这六大组件相互之间紧密配合,提供了丰富而强大的功能,使得开发人员能够更高效地进行数据管理、算法处理和代码编写。 下面对这些组件进行简单的介绍(后面的文章也会对这些逐一分析)
- 容器(Containers):容器是STL中用于存储数据的组件。STL提供多种容器类,像向量(vector)、链表(list)、队列(queue)、栈(stack)、集合(set)、映射(map)等。每种容器都有特定的特性和适用场景,开发人员可以根据需求选择合适的容器类来管理数据。
- 算法(Algorithms):算法是STL中的核心部分。它提供了丰富的函数模板,用于处理容器中的元素。STL的算法包括排序、搜索、复制、变换等功能,比如
sort
、find
、copy
等。算法通常通过迭代器来操作容器,因此可以很方便地应用于各种容器,并且具有良好的可重用性和效率。 - 迭代器(Iterators):迭代器是STL中的通用遍历机制。它相当于指针一样,用于遍历容器中的元素。迭代器提供了对容器元素的访问和操作方法,使得算法可以在不依赖具体容器类型的情况下进行工作。STL提供了多种类型的迭代器,包括输入迭代器、输出迭代器、正向迭代器、双向迭代器和随机访问迭代器,根据容器和算法的要求选择合适的迭代器类型。
- 函数对象(Function Objects):函数对象是可以像函数一样调用的对象。STL中的算法和某些容器类使用函数对象来指定操作的方式,如排序顺序、元素匹配等。STL提供了一些已定义的函数对象,比如等于判断(
equal_to
)、比较大小(less
)、取反(not
)等,也可以自定义函数对象来适应特定需求。 - 适配器(Adapters):适配器是STL中的一种特殊组件。它可以将一种容器或迭代器的接口转换为另一种接口,以便于在不同上下文中使用。STL提供了多种适配器,如堆栈适配器(
stack
)、队列适配器(queue
)和优先队列适配器(priority_queue
),它们在底层使用其他容器类,通过适配器接口提供不同的行为。 - 分配器(Allocators):分配器用于管理容器使用的内存分配和释放。STL提供了默认的分配器(
allocator
),也允许开发人员定义自己的分配器。分配器可以根据具体的内存需求进行内存管理,以提高效率和灵活性。
编辑
3.STL的使用前提
- 了解C++基础知识:STL是建立在C++语言的基础上的,因此使用STL需要对C++基础知识有一定的了解,包括类、继承、模板等概念。
- 熟悉STL的组件:要使用STL,需要对STL的六大组件(容器、算法、迭代器、函数对象、适配器和分配器)有一定的了解,知道它们的特性、用法以及如何选择合适的组件来解决问题。
- 理解模板编程:STL使用了模板编程的技术,在使用STL时需要理解模板的基本语法以及模板的实例化和函数重载等机制。
二、string类
1.string类 是什么
在C++中,std::string
是标准库提供的一个类,用于处理字符串。它是基于模板的容器类,位于命名空间std
中。std::string
类提供了许多成员函数和操作符,用于对字符串进行各种操作,比如插入、删除、查找、连接等。与C风格的字符串相比,std::string
类更加安全和方便,它负责自动管理字符串内存,具有动态大小调整的能力。
2.string类的特点和操做
⭕构造和初始化
string类提供了多种构造函数和初始化方式,用于创建和初始化字符串对象。以下是 std::string 类的构造函数和初始化方式的介绍:
✅默认构造函数
string();
创建一个空的字符串对象。
✅字符串常量初始化
string(const char* s); string(const char* s, size_type count);
使用C风格字符串 s 来初始化字符串对象。传入的字符串可以是以 null 字符结尾的字符数组( const char*),或者可以指定字符个数( size_type count)。
✅复制构造函数
string(const string& other);
使用一个已有的字符串对象 other 来创建一个新的字符串对象。新对象是 other 的副本,内容相同。
✅填充构造函数
string(size_type count, char ch);
创建一个包含 count 个字符 ch 的字符串对象。
✅迭代器范围初始化
template <class InputIt> string(InputIt first, InputIt last);
使用迭代器指定的字符范围 [first, last) 来初始化字符串对象。这使得可以使用其他容器或字符数组等作为初始化源。
✅初始化列表初始化
string(initializer_list<char> ilist);
使用初始化列表来初始化字符串对象。
除了构造函数,还可以使用赋值运算符 = 将一个字符串对象赋值给另一个字符串对象。
std::string str8 = str1; // 使用赋值运算符 str1 = str2; // 使用赋值运算符
通过这些构造函数和初始化方式,可以创建并初始化字符串对象,以便对其进行后续的字符串操作和处理。
✅初始化总结
int main() { std::string str1; // 默认构造函数 std::string str2("Hello"); // 字符串常量初始化 std::string str3("Hello", 3); // 字符串常量初始化,指定字符个数 std::string str4(str2); // 复制构造函数,创建副本 std::string str5(5, 'A'); // 填充构造函数,创建包含5个字符'A'的字符串 std::string str6(str2.begin(), str2.end());// 迭代器范围初始化 std::string str7{'C', 'P', 'P'}; // 初始化列表初始化 std::string str8 = str1; // 使用赋值运算符 str1 = str2; // 使用赋值运算符 return 0; }
⭕字符串大小和容量
在 std::string 类中,可以使用成员函数来获取字符串的大小和容量。
✅字符串大小
size() , length() : 返回字符串中字符的个数(即字符串的长度)。
std::string str = "Hello"; std::cout << str.size(); // 输出:5 std::cout << str.length(); // 输出:5
✅字符串容量
capacity() : 返回字符串内存分配的容量,即字符串可以容纳的字符数,而不会进行重新分配。
reserve(size_type count) : 请求将字符串的容量设置为至少 count 个字符。
shrink_to_fit() : 要求字符串按照实际大小来分配内存,即缩小容量以适应当前字符串的大小。
std::string str = "Hello"; std::cout << str.capacity(); // 输出:15 str.reserve(20); std::cout << str.capacity(); // 输出:20 str.shrink_to_fit(); std::cout << str.capacity(); // 输出:5
🚨注意
- 字符串的大小是指字符的个数,而不是字符串占用的字节数。一个字符可以占用多个字节的存储空间,例如UTF-8编码中的某些特殊字符。
- 字符串的容量不一定等于大小。字符串的容量取决于内存的分配策略和字符串的动态增长过程。通常情况下,当增加字符串长度时,字符串会自动重新分配更大的内存块,以容纳新的字符,从而增加容量。
- 调用
reserve()
函数可以预留一定的容量,避免频繁的内存重新分配,提高性能。但是并不总是需要手动调用reserve()
,因为std::string
类会根据实际需要自动调整容量。
通过上面这些函数,可以方便地获取和管理字符串的大小和容量信息。
⭕字符访问和修改
在std::string
类中,提供了多种方法来访问和修改字符串中的字符,通过下面这些函数,可以方便地访问和修改字符串中的特定字符,或者在字符串的末尾添加或删除字符。
✅字符访问
operator[](size_type pos)
: 使用下标操作符[]
来访问指定位置pos
处的字符。at(size_type pos)
: 使用at()
函数来访问指定位置pos
处的字符,并进行边界检查。front()
: 获取字符串的第一个字符。back()
: 获取字符串的最后一个字符。
std::string str = "Hello"; char ch1 = str[0]; // 使用下标操作符访问首字符,ch1='H' char ch2 = str.at(2); // 使用at()函数访问第三个字符,ch2='l' char ch3 = str.front(); // 获取字符串的第一个字符,ch3='H' char ch4 = str.back(); // 获取字符串的最后一个字符,ch4='o'
✅字符修改
operator[](size_type pos)
: 使用下标操作符[]
来修改指定位置pos
处的字符。at(size_type pos)
: 使用at()
函数来修改指定位置pos
处的字符,并进行边界检查。push_back(char ch)
: 在字符串的末尾添加一个字符。pop_back()
: 删除字符串的末尾字符。clear()
: 清空字符串中的所有字符。resize(size_type count)
: 改变字符串的大小。新的大小会影响字符串的字符个数。resize(size_type count, char ch)
: 改变字符串的大小,并用指定字符ch
填充新增部分。
std::string str = "Hello"; str[0] = 'h'; // 使用下标操作符修改首字符,字符串变为"hello" str.at(3) = 'P'; // 使用at()函数修改第四个字符,字符串变为"helPo" str.push_back('!'); // 在末尾添加字符'!',字符串变为"helPo!" str.pop_back(); // 删除末尾的字符,字符串变为"helPo" str.clear(); // 清空字符串,字符串成为空字符串 str.resize(7); // 改变字符串大小为7,添加空字符,即字符串变为"helPo\0\0" str.resize(10, '*'); // 改变字符串大小为10,用'*'填充剩余部分,即字符串变为"helPo****"
⭕字符串连接和拼接
在std::string
类中,提供了多种方法来进行字符串的连接和拼接操作,以合并多个字符串为一个字符串,这些方法可以通过操作符重载和成员函数来实现。
✅字符串连接
operator+
:使用 +
操作符将两个字符串连接起来,产生一个新的字符串。
operator+=
:使用 +=
操作符将一个字符串追加到另一个字符串的末尾,修改原字符串。
std::string str1 = "Hello"; std::string str2 = "World"; std::string str3 = str1 + str2; // 使用+操作符进行字符串连接,得到字符串"HelloWorld" str1 += str2; // 使用+=操作符将str2追加到str1的末尾,修改str1的值为"HelloWorld"
✅字符串拼接
append(const char* s)
:将一个以 null 字符结尾的字符数组(C风格字符串)追加到当前字符串的末尾。
append(const std::string& str)
:将另一个字符串追加到当前字符串的末尾。
append(const char* s, size_type count)
:将指定个数的字符从一个以 null 字符结尾的字符数组(C风格字符串)追加到当前字符串的末尾。
std::string str = "Hello"; str.append(" World"); // 将C风格字符串追加到字符串末尾,字符串变为"Hello World" std::string otherStr = " from C++"; str.append(otherStr); // 将另一个字符串追加到字符串末尾,字符串变为"Hello World from C++"
以上方法可以灵活地进行字符串的连接和拼接操作,使用不同的方法可以根据具体需求选择最合适的方式来实现字符串的合并。
⭕子串操作
在 std::string
类中,提供了多种方法来进行子串操作,即从一个字符串中获取部分字符组成新的子串。这些方法可以用于检索、提取和操作字符串的特定部分。
✅substr()
函数
substr(pos, count)
:从位置 pos
开始,提取长度为 count
的子串。
std::string str = "Hello, World!"; std::string sub1 = str.substr(0, 5); // 获取从位置0开始的5个字符,得到子串"Hello" std::string sub2 = str.substr(7); // 获取从位置7开始到末尾的子串,得到子串"World!"
✅getline()
函数
getline(input_stream, str, delimiter)
:从输入流 input_stream
中读取一行字符,并将结果存储在字符串 str
中,以指定的分隔符 delimiter
结束,分隔符默认为换行符。
std::string input; std::getline(std::cin, input); // 从标准输入读取一行字符,存储在input字符串中
✅find()
函数
find(substring, pos)
:从位置 pos
开始,在字符串中搜索子串 substring
,返回第一次出现的位置;如果未找到,返回std::string::npos
std::string str = "Hello, World!"; size_t pos = str.find("World"); // 在字符串中搜索子串"World",得到位置7
✅rfind()
函数
rfind(substring, pos)
:从字符串中的pos
位置开始,从后向前搜索子串substring
,返回最后一次出现的位置。如果找不到子串,则返回std::string::npos
。
std::string str = "Hello, World!"; size_t pos = str.rfind("o"); // 从位置12开始,从后向前搜索字符"o",得到位置8
✅find_first_of()
函数
find_first_of(chars, pos)
:从字符串中的pos
位置开始,搜索位于字符集chars
中的任何一个字符第一次出现的位置。如果找不到任何字符,则返回std::string::npos
std::string str = "Hello, World!"; size_t pos = str.find_first_of("Wdl"); // 从位置0开始,在字符串中搜索字符集"Wdl"中的任一字符,得到位置2(字符"l"第一次出现的位置)
✅find_last_of()
函数
find_last_of(chars, pos)
:从字符串中的pos
位置开始,从后向前搜索位于字符集chars
中的任何一个字符最后一次出现的位置。如果找不到任何字符,则返回std::string::npos
std::string str = "Hello, World!"; size_t pos = str.find_last_of("odl"); // 从位置12开始,从后向前搜索字符集"odl"中的任一字符,得到位置10(字符"l"最后一次出现的位置)
✅replace()
函数:
replace(pos, count, new_string)
:从位置 pos
开始,替换长度为 count
的子串为 new_string
std::string str = "Hello, World!"; str.replace(7, 5, "Everyone"); // 从位置7开始,将长度为5的子串"World"替换为字符串"Everyone"
通过这些子串操作方法,可以方便地提取特定的子串、查找特定的字符位置、替换子串等,以满足具体的字符串处理需求。
⭕字符串比较
在std::string
类中,提供了多种方法来进行字符串的比较操作,用于判断两个字符串是否相等或者确定它们的大小关系。这些方法可以通过操作符重载和成员函数来实现。
✅操作符重载
==
:检查两个字符串是否相等。!=
:检查两个字符串是否不相等。<
:检查第一个字符串是否小于第二个字符串(按字典序比较)。>
:检查第一个字符串是否大于第二个字符串(按字典序比较)。<=
:检查第一个字符串是否小于等于第二个字符串(按字典序比较)。>=
:检查第一个字符串是否大于等于第二个字符串(按字典序比较)。
std::string str1 = "Hello"; std::string str2 = "World"; bool isEqual = (str1 == str2); // 判断两个字符串是否相等 bool isNotEqual = (str1 != str2); // 判断两个字符串是否不相等 bool isLess = (str1 < str2); // 判断str1是否小于str2 bool isGreater = (str1 > str2); // 判断str1是否大于str2 bool isLessOrEqual = (str1 <= str2); // 判断str1是否小于等于str2 bool isGreaterOrEqual = (str1 >= str2); // 判断str1是否大于等于str2
✅成员函数
compare(str)
:按字典序比较当前字符串和参数字符串str
。返回一个整数,表示比较结果。
- 返回值 < 0:当前字符串小于
str
。 - 返回值 > 0:当前字符串大于
str
。 - 返回值 = 0:当前字符串等于
str
。
std::string str1 = "Hello"; std::string str2 = "World"; int result = str1.compare(str2); // 比较str1和str2
⭕字符串修改
在std::string
类中,提供了多种方法来修改字符串的内容,这些方法可以用于插入、删除、替换字符或子串,以及改变字符串的大小等操作。
✅插入字符或子串
insert(pos, str)
:在指定位置 pos
前插入字符串 str
insert(pos, str, subpos, sublen)
:在指定位置 pos
前插入字符串 str
的子串,子串长度为 sublen
,起始位置为 subpos
std::string str = "Hello"; str.insert(5, "World"); // 在位置5前插入字符串"World",得到字符串"HelloWorld" str.insert(0, "I am ", 2, 4);// 在位置0前插入字符串"I am "的子串"am ",得到字符串"am HelloWorld"
✅删除字符或子串
erase(pos, count)
:从指定位置 pos
开始,删除 count
个字符。
std::string str = "Hello, World!"; str.erase(5, 7); // 从位置5开始删除7个字符,得到字符串"Hello!"
✅替换字符或子串
replace(pos, count, str)
:从指定位置 pos
开始,将长度为 count
的子串替换为字符串 str
std::string str = "Hello, World!"; str.replace(7, 5, "Everyone"); // 从位置7开始,将长度为5的子串"World"替换为字符串"Everyone",得到字符串"Hello, Everyone!"
✅改变字符串大小
resize(new_size)
:改变字符串的大小为 new_size
,截断或填充空字符。
resize(new_size, fill)
:改变字符串的大小为 new_size
,使用字符 fill
填充。
std::string str = "Hello"; str.resize(10); // 将字符串大小改变为10,默认用空字符填充,得到字符串"Hello " str.resize(7, '!'); // 将字符串大小改变为7,用字符'!'填充,得到字符串"Hello!!"
通过这些字符串修改方法,可以方便地插入、删除、替换字符或子串,以及改变字符串的大小,以满足不同的字符串处理需求。根据具体情况选择最适合的方法来修改字符串。
⭕获取字符的ASCII码
在C++的std::string
类中,可以使用索引操作符[]
或成员函数at()
来获取字符串中特定位置字符的ASCII码。
✅索引操作符[]
str[index]
:返回字符串str
中位置为index
的字符的ASCII码。请注意,索引从0开始。
std::string str = "Hello"; char ch = str[0]; // 获取字符串第一个字符'H' int ascii = static_cast<int>(ch); // 转换字符为ASCII码
✅成员函数at()
:
str.at(index)
:返回字符串str
中位置为index
的字符的ASCII码。如果索引超出了字符串的范围,at()
函数会抛出std::out_of_range
std::string str = "Hello"; char ch = str.at(1); // 获取字符串第二个字符'e' int ascii = static_cast<int>(ch); // 转换字符为ASCII码
在上面的代码中,我们先获取到字符串中特定位置的字符,然后使用static_cast<int>(ch)
将字符转换为相应的ASCII码。注意,将字符转换为整数类型可以使用static_cast
来进行显式类型转换。
⭕字符串大小写转换:
在C++的std::string
类中,提供了一些方法来进行字符串的大小写转换操作。这些方法可以将字符串中的字符转换为大写或小写形式。
✅换为大写
toupper()
函数:将字符串中的字符转换为大写形式。
std::string str = "Hello, World!"; for (char& c : str) { c = std::toupper(c); // 将字符转换为大写形式 }
✅换为小写
tolower()
函数:将字符串中的字符转换为小写形式。
std::string str = "Hello, World!"; for (char& c : str) { c = std::tolower(c); // 将字符转换为小写形式 }
在上面的代码中,我们使用循环遍历字符串中的每个字符,并通过std::toupper()
和std::tolower()
函数将其转换为大写或小写形式。请注意,这些函数返回转换后的字符,并且在循环中我们通过引用来修改原始字符串。
✅C++标准库转换
除了使用循环遍历字符进行转换,还可以使用C++标准库算法和字符串迭代器来实现字符串的大小写转换:
#include <algorithm> #include <cctype> std::string str = "Hello, World!"; std::transform(str.begin(), str.end(), str.begin(), ::toupper); // 将字符串转换为大写形式 std::transform(str.begin(), str.end(), str.begin(), ::tolower); // 将字符串转换为小写形式
在上面的代码中,我们使用std::transform()
算法和字符处理函数::toupper
和::tolower
来实现字符串的大小写转换。::toupper
和::tolower
是函数指针,用于执行字符的大写和小写转换。
总结
本文通过对STL(Standard Template Library)和string类的介绍,为读者提供了对STL和string类的全面了解。在STL简介部分,我们了解到STL是C++标准库的重要组成部分,分别是容器、算法、迭代器、函数对象、适配器和分配器六个核心内容,使用前需要掌握C++的基本语法和模板的使用。在string类部分,我们深入研究了string类的定义、特点和常见操作。构造和初始化包括使用初始化列表初始化和初始化总结,字符串大小和容量提供了获取字符串大小和容量的方法,字符访问和修改可以方便地操作字符串的字符,字符串连接和拼接可以合并字符串,子串操作可以从字符串中提取子串。字符串比较提供了多种方法来比较字符串的大小关系,字符串修改可以插入、删除和替换字符或子串,获取字符的ASCII码可以得到字符的ASCII码值,而字符串大小写转换可以将字符串转换为大写或小写形式。通过本文的学习,读者将掌握STL的基本概念和string类的常用操作,从而能够更加灵活和高效地处理和操作字符串。
温馨提示
感谢您对博主文章的关注与支持!在阅读本篇文章的同时,我们想提醒您留下您宝贵的意见和反馈。如果您喜欢这篇文章,可以点赞、评论和分享给您的同学,这将对我提供巨大的鼓励和支持。另外,我计划在未来的更新中持续探讨与本文相关的内容。我会为您带来更多关于C++以及编程技术问题的深入解析、应用案例和趣味玩法等。请继续关注博主的更新,不要错过任何精彩内容!
再次感谢您的支持和关注。我们期待与您建立更紧密的互动,共同探索C++、算法和编程的奥秘。祝您生活愉快,排便顺畅!
编辑