C++中string常用方法总结
📝前言:
STL(standard template libaray-标准模板库):是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架。今天就让我们先学习STL中的重要容器之一——string(文中表粗为重要用法)
🎬个人简介:努力学习ing
📋个人专栏:C++学习笔记
🎀CSDN主页 愚润求学
🌄其他专栏:C语言入门基础,python入门基础,python刷题专栏
文章目录
- 一,了解STL
- 二,string常用接口
- 1. 构造函数
- 2. 赋值操作
- 3. 元素访问及遍历
- 4. 大小和容量操作
- 5. 修改操作
- 6. 子字符串操作
- 7. 查找操作
- 8. 比较操作
- 10. C 风格字符串转换
- 11. getline
一,了解STL
STL 最初由 Alexander Stepanov 等人开发,后被纳入 C++ 标准。STL 有标准规范,但是,不同公司为了提高性能,或者其他原因,在实现 STL 时,在底层数据结构和算法的选择上可能会有差异。比如,Visual C++ 编译器中自带的 STL 实现和GCC 编译器中的 STL 实现就有所差异。
- STL主要由以下六个部分组成:
在学习STL的时候,更多是一个探索过程,我们要多查文档了解用法,在实践和练习中学习。https://legacy.cplusplus.com/reference/这个文档按头文件整理,虽然不是官方的,但是对初学者较为友好。
二,string常用接口
在 C++ 里,std::string
是标准库中的类,它处于 std
命名空间中。
首先介绍一下string
和C风格字符串的区别:
string s1("hello world");char s2[] = "hello world";
对于上面两个字符串在内存中的存储,s1
不带\0
,s2
带\0
所以对于C风格的字符串,我们无法直接使用string
的方法,对于string类型的字符串,我们要使用C风格字符串的方法需要通过c_str()
转换成C风格的字符串,因为C风格的字符串操作大多是需要使用\0
的。
1. 构造函数
string()
: 默认构造函数,创建一个空字符串。string(const char* s)
: 用 C 风格字符串初始化。string(const string& str)
: 拷贝构造函数。string(size_t n, char c)
: 创建一个包含n
个字符c
的字符串。
示例:
std::string s1; // 空的string类对象// 使用 C 风格字符串初始化std::string s2("Hello, World!");// 使用拷贝构造函数,用 s2 初始化 s3std::string s3(s2);// 创建一个包含 5 个字符 'A' 的字符串std::string s4(5, 'A');
2. 赋值操作
string& operator=(const string& str)
: 赋值操作符。
std::string str1 = "Initial value"; // 这是拷贝构造初始化std::string str2;// 使用赋值操作符 = 将 str1 的内容赋给 str2str2 = str1;
3. 元素访问及遍历
char& operator[](size_t pos)
: 访问指定位置的字符(不检查边界)。就和使用数组下标一样。
std::string str = "Hello, World!";// 使用 operator[] 访问指定位置的字符(不检查边界)// 修改指定位置的字符str[0] = 'h';
==迭代器==是学习容器非常重要的一个概念,迭代器类似指针,也可以加减来移动,但是不能大小比较,且不同类型的迭代器不能比较(如iterator
和reverse_iterator
类型不能比较)
iterator begin()
: 返回指向字符串开头的迭代器。iterator end()
: 返回指向字符串末尾的迭代器。reverse_iterator rbegin()
: 返回指向字符串末尾的反向迭代器。reverse_iterator rend()
: 返回指向字符串开头的反向迭代器。
利用迭代器访问:
int main() {std::string str = "Hello, World!";// 使用 begin() 和 end() 正向遍历字符串std::cout << "正向遍历字符串: ";for (std::string::iterator it = str.begin(); it != str.end(); ++it) {std::cout << *it;}std::cout << std::endl;// 使用 rbegin() 和 rend() 反向遍历字符串std::cout << "反向遍历字符串: ";for (std::string::reverse_iterator rit = str.rbegin(); rit != str.rend(); ++rit) {std::cout << *rit;}std::cout << std::endl;return 0;
}
输出:
正向遍历字符串: Hello, World!
反向遍历字符串: !dlroW ,olleH
auto
用于自动推到类型,常用在替换较长的代码名称。
注意:auto
声明的变量必须有初始值,因为编译器需要根据初始值来推导类型。且auto
不能用在函数参数
利用auto
和范围for
访问:
// 使用范围 for 和 auto 访问for (auto ch : str) {std::cout << ch;}return 0;
}
4. 大小和容量操作
size_t size() const
: 返回字符串的长度。size_t length() const
: 与size()
相同,返回字符串的长度。bool empty() const
: 判断字符串是否为空。void resize(size_t n)
: 调整字符串的大小。size_t capacity() const
: 返回当前分配的存储空间大小。void reserve(size_t n)
: 预留存储空间。void clear()
: 清空字符串。(但是开的空间不清)
#include <iostream>
#include <string>int main() {// 定义一个字符串对象并初始化为 "Hello"std::string str = "Hello";// 使用 size() 方法返回字符串的长度// 这里输出字符串使用 size() 方法得到的长度std::cout << "使用 size() 方法得到的字符串长度: " << str.size() << std::endl;// 使用 length() 方法返回字符串的长度// length() 和 size() 功能一样,这里输出使用 length() 方法得到的长度std::cout << "使用 length() 方法得到的字符串长度: " << str.length() << std::endl;// 使用 empty() 方法判断字符串是否为空// 根据 empty() 的返回结果输出字符串是否为空的信息std::cout << "字符串是否为空? " << (str.empty() ? "是" : "否") << std::endl;// 使用 resize() 方法调整字符串的大小// 将字符串大小调整为 10,如果新长度大于原长度,用 '!' 填充,如果新长度小于原长度,则截断str.resize(10, '!');// 输出调整大小后的字符串std::cout << "调整大小为 10 并用 '!' 填充后的字符串: " << str << std::endl;// 输出调整大小后字符串的新长度std::cout << "调整大小后的新长度: " << str.size() << std::endl;// 使用 capacity() 方法返回当前为字符串分配的存储空间大小std::cout << "当前字符串分配的存储空间大小: " << str.capacity() << std::endl;// 使用 reserve() 方法预留存储空间// 预留至少能容纳 20 个字符的存储空间str.reserve(20);// 输出预留存储空间后的容量std::cout << "预留 20 个字符存储空间后的容量: " << str.capacity() << std::endl;// 使用 clear() 方法清空字符串str.clear();// 再次使用 empty() 方法判断字符串是否为空并输出结果std::cout << "清空字符串后是否为空? " << (str.empty() ? "是" : "否") << std::endl;return 0;
}
运行结果:
说明:为什么预留
reserve(20)
但是开的capacity
是31
?
首先,先了解一下string
的自动扩容:
当向string
中添加字符,使得字符数量超过其当前分配的容量capacity
时,string
会自动进行扩容操作。但是,不同的标准库实现可能采用不同的扩容策略,但常见的做法是按照一定的倍数进行扩容。例如,当需要扩容时,可能会将容量扩大为原来的2 倍,这样可以减少频繁扩容带来的性能开销。
所以当我们reserve(20)
的时候,编译器会根据自己的标准进行扩容,确保开的空间是>=20
的。
对于reserve(n)
,如果n比目前的字符串小,就不会执行,但是如果比capacity
小,比字符串大则可能执行,由编译器决定.
5. 修改操作
string& append(const string& str)
: 在字符串末尾追加字符串。string& operator+=(const string& str)
: 追加字符串。void push_back(char c)
: 在字符串末尾追加一个字符。string& insert(size_t pos, const string& str)
: 在指定位置插入字符串。string& erase(size_t pos = 0, size_t len = npos)
: 删除从pos
开始的len
个字符。string& replace(size_t pos, size_t len, const string& str)
: 替换从pos
开始的len
个字符为str
。
示例:
int main()
{std::string str = "Hello";// 使用 append(const string& str) 在字符串末尾追加字符串std::string appendStr = ", World";str.append(appendStr);std::cout << "使用 append 追加后: " << str << std::endl;// 使用 operator+=(const string& str) 追加字符串std::string anotherAppend = "!";str += anotherAppend;std::cout << "使用 += 追加后: " << str << std::endl;// 使用 push_back(char c) 在字符串末尾追加一个字符str.push_back('?');std::cout << "使用 push_back 追加字符后: " << str << std::endl;// 使用 insert(size_t pos, const string& str) 在指定位置插入字符串std::string insertStr = " amazing";str.insert(5, insertStr);std::cout << "在位置 5 插入字符串后: " << str << std::endl;// 使用 erase(size_t pos = 0, size_t len = npos) 删除从 pos 开始的 len 个字符str.erase(5, insertStr.length());std::cout << "删除插入的字符串后: " << str << std::endl;// 使用 replace(size_t pos, size_t len, const string& str) 替换从 pos 开始的 len 个字符为 strstd::string replaceStr = "Hi";str.replace(0, 5, replaceStr);std::cout << "替换前 5 个字符后: " << str << std::endl;return 0;
}
运行结果:
6. 子字符串操作
string substr(size_t pos = 0, size_t len = npos) const
: 返回从pos
开始的len
个字符组成的子字符串。
示例:
std::string mainStr = "Hello, Hello, World!";std::string Sub = mainStr.substr(3, 7);std::cout << Sub << std::endl; // 输出:lo, Hel
7. 查找操作
size_t find(const string& str, size_t pos = 0) const
: 从pos
开始查找子字符串str
。size_t rfind(const string& str, size_t pos = npos) const
: 从pos
开始反向查找子字符串str
。find_first_of
:有多个函数重载,用于在字符串中查找指定字符集合中任意一个字符首次出现的位置。find_last_of
:与find_first_of
类似,从字符串的末尾开始向前查找,用于在字符串中查找指定字符集合中任意一个字符最后一次出现的位置。
npos
是 static const size_t
类型的-1
,但是size_t
是一种无符号整数类型,所以以补码的形式存储-1
就相当于一个很大的数
示例:
#include <iostream>
#include <string>int main() {std::string mainStr = "Hello, Hello, World!";std::string subStr = "Hello";// 使用 find(const string& str, size_t pos = 0) 从 pos 开始查找子字符串 strsize_t foundPos = mainStr.find(subStr, 0);if (foundPos != std::string::npos) {std::cout << "使用 find 从位置 0 开始查找,首次找到 \"" << subStr << "\" 的位置是: " << foundPos << std::endl;}else {std::cout << "使用 find 从位置 0 开始查找,未找到 \"" << subStr << "\"。" << std::endl;}// 从位置 7 开始查找foundPos = mainStr.find(subStr, 7);if (foundPos != std::string::npos) {std::cout << "使用 find 从位置 7 开始查找,找到 \"" << subStr << "\" 的位置是: " << foundPos << std::endl;}else {std::cout << "使用 find 从位置 7 开始查找,未找到 \"" << subStr << "\"。" << std::endl;}// 使用 rfind(const string& str, size_t pos = npos) 从 pos 开始反向查找子字符串 strsize_t rfoundPos = mainStr.rfind(subStr);if (rfoundPos != std::string::npos) {std::cout << "使用 rfind 反向查找,最后一次找到 \"" << subStr << "\" 的位置是: " << rfoundPos << std::endl;}else {std::cout << "使用 rfind 反向查找,未找到 \"" << subStr << "\"。" << std::endl;}return 0;
}
运行结果:
find_frst_of
示例:
std::string str = "Hello, World!";// 查找字符串中任意一个数字字符首次出现的位置std::string digits = "0123456789";size_t found1 = str.find_first_of(digits);// 从位置 5 开始查找字符串中任意一个标点符号首次出现的位置std::string punctuations = ".,!?;:";size_t found2 = str.find_first_of(punctuations, 5);// 查找字符串中字符 'o' 首次出现的位置size_t found3 = str.find_first_of('o');
find_last_of
示例:
std::string str = "Hello, World!";// 查找字符串中任意一个字母字符最后一次出现的位置std::string letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";size_t found1 = str.find_last_of(letters);// 从位置 8 开始向前查找字符串中任意一个标点符号最后一次出现的位置std::string punctuations = ".,!?;:";size_t found2 = str.find_last_of(punctuations, 8);// 查找字符串中字符 'l' 最后一次出现的位置size_t found3 = str.find_last_of('l');
8. 比较操作
bool operator==(const string& str) const
: 判断两个字符串是否相等。bool operator!=(const string& str) const
: 判断两个字符串是否不相等。int compare(const string& str) const
: 比较两个字符串
C ++字符串支持常见的比较操作符(>,>=,<,<=,==,!=),甚至支持string与C-string的比较(如 str<”hello”)。 因为会发生隐式类型转换,把C风格的转换成string
示例:
compare
方法提供了更多的重载形式,支持用索引值和长度定位子串来进行比较,功能灵活
#include <iostream>
#include <string>int main() {std::string str1 = "apple pie";std::string str2 = "applesauce";// 比较 str1 从位置 0 开始的 5 个字符和 str2 从位置 0 开始的 5 个字符int result = str1.compare(0, 5, str2, 0, 5);if (result == 0) {std::cout << "str1 和 str2 的前 5 个字符相等" << std::endl;}return 0;
}
10. C 风格字符串转换
const char* c_str() const
: 返回一个指向 C 风格字符串的指针。
示例:
#include <iostream>
#include <string>
#include <cstring>int main() {std::string str1 = "apple";std::string str2 = "banana";// 使用 c_str() 转换为 C 风格字符串const char* cstr1 = str1.c_str();const char* cstr2 = str2.c_str();// 使用 C 风格的 strcmp 函数比较两个字符串int result = strcmp(cstr1, cstr2);if (result < 0) {std::cout << "str1 小于 str2" << std::endl;}else if (result > 0) {std::cout << "str1 大于 str2" << std::endl;}else {std::cout << "str1 等于 str2" << std::endl;}return 0;
}
11. getline
getline
用于从输入流(标准或文件)中读取一行文本(默认以\n
作为分隔符)
scanf
和cin
默认是以空白字符(空格、制表符、换行符等)作为分隔来读取数据的。
函数原型:
std::istream& getline(std::istream& is, std::string& str, char delim);
is
:输入流对象,通常是 std::cin 用于从标准输入读取数据。str
:用于存储读取到的一行文本的 std::string 对象。delim
(可选):分隔符,默认是换行符\n
。当遇到该分隔符时,读取停止(不会读取分隔符)。
示例:
#include <iostream>
#include <string>int main() {std::string line;std::cout << "请输入一行文本:";// 使用默认分隔符(换行符)读取一行std::getline(std::cin, line);std::cout << "你输入的文本是:" << line << std::endl;return 0;
}
🌈我的分享也就到此结束啦🌈
要是我的分享也能对你的学习起到帮助,那简直是太酷啦!
若有不足,还请大家多多指正,我们一起学习交流!
📢公主,王子:点赞👍→收藏⭐→关注🔍
感谢大家的观看和支持!祝大家都能得偿所愿,天天开心!!!