cpp
# 1. 字符串类型
在C语言中,没有字符串类型的。C语言中使用字符数组/字符指针来表示一串字符。
```cpp
char str[128] = "hello"; // 栈区,可以修改
str[0] = 'H'; // 正确
char *p_str = "hello"; // 常量区
// p_str[0] = 'H'; // 错误 常量区的内容不能修改在C++标准库中,提供了一个字符串类型,实际上是一个字符串类。类名叫做string,专门用于描述一个字符串对象,并且提供了操作字符串的一系列函数接口。
1.1 使用方法
指定作用域,因为是标准库中的,所以要使用std的命名空间。
cpp
std::string str = "蔡徐坤";1.2 字符串对象的实例化方式
- 无参构造函数方式
cpp
std::string str; // 空字符串- 含参构造方式
cpp
std::string str("蔡徐坤");
// 或
std::string str = std::string("范丞丞");- 使用字符和长度作为参数的构造函数
cpp
std::string str2("abcdefg", 3); // "abc"- 拷贝构造
cpp
std::string str1 = std::string("范丞丞");
std::string str2(str1);
// 或
std::string str2 = str1;
// 使用字符数组
char c[] = "范丞丞";
std::string str2(c);- 拷贝赋值
cpp
std::string str1 = std::string("范丞丞");
std::string str2("蔡徐坤");
str2 = str1;
// 使用字符数组
char c[] = "范丞丞";
std::string str2("蔡徐坤");
str2 = c;1.3 常用的成员函数(访问元素)
at(int size)
访问指定字符,有边界检查,返回指定位置的字符的引用
cpp
std::string str("abcdefg");
char c = str.at(3); // 'd'
std::cout << c << std::endl; // 如果越界会崩溃operator[]
下标访问
cpp
std::string str("abcdefg");
char c = str[3]; // 'd'
std::cout << c << std::endl;front()
访问首字符
cpp
std::string str("abcdefg");
char c = str.front(); // 'a'
std::cout << c << std::endl;back()
访问最后有效字符
cpp
std::string str("abcdefg");
char c = str.back(); // 'g'
std::cout << c << std::endl;data()
返回指向字符串首字符的指针
cpp
std::string str("abcdefg");
const char *p = str.data();
std::cout << p << std::endl; // "abcdefg"
std::cout << std::hex << (void *)p << std::endl; // 地址c_str()
返回指向字符串首字符的指针,同 data()
cpp
std::string str("abcdefg");
const char *p = str.c_str();
std::cout << p << std::endl;关键差异在于:c_str() 会在数据末尾自动添加一个终止符 \0,而 data() 不会!
1.4 容量相关函数
empty()
检查字符串是否为空,返回布尔值
cpp
string str = "abcdefg";
cout << str.empty() << endl; // 0 (false)size()/length()
返回有效字符长度
cpp
string str = "abcdefg";
cout << str.size() << endl; // 7
cout << str.length() << endl; // 7
cout << sizeof(str) << endl; // 40 (平台相关)max_size()
返回std::string类型对象所能容纳的最大字符数
cpp
string str = "abcdefg";
cout << str.max_size() << endl; // 9223372036854775807 (理论最大值)reserve(size_t size)
预留字符串对象的内存空间
cpp
string str = "abcdefg";
str.reserve(100); // 预留至少100字符内存capacity()
返回当前已分配内存可容纳的最大字符数
cpp
string str = "abcdefg";
std::cout << "length: " << str.length() << std::endl;
std::cout << "capacity: " << str.capacity() << std::endl;1.5 字符串操作
clear()
清除内容
cpp
std::string str = "Hello";
str.clear();
cout << "str = " << str << endl; // 空字符串insert(size_t pos, 字符串)
插入字符串
cpp
std::string str = "Hello";
str.insert(1, "abc"); // 在位置1插入
cout << "str = " << str << endl; // "Habcello"find(字符串)
查找子串,返回第一次出现的索引
cpp
std::string str = "abcdefg";
size_t pos = str.find("def");
if (pos != std::string::npos) {
cout << "Found at position: " << pos << endl; // 3
}2. 迭代器模式
2.1 设计模式概述
设计模式是一种在软件设计中常用的解决问题的方法或模板。它们描述了在特定情境下的问题和解决方案,并提供了一种被广泛接受的方法来设计和构建软件系统。
设计模式可以帮助开发人员解决常见的设计问题,并提供一种可重用的、经过验证的方法来构建高质量的软件系统。它们被视为一种优秀的实践,可以提高代码的可维护性、可扩展性和可重用性。
2.2 迭代器模式
在软件开发的过程中,集合内部的结构经常发生改变。对于这些集合对象,用户希望在可以不了解内部结构的同时,可以让外界透明的访问其中的元素,不管集合内部的数据结构如何变化,反正对于集合外部的访问接口都保持不变。
这种"让外界透明的访问"为同一种接口(begin/end)可以在多种集合对象上进行同一种操作。
使用面向对象的技术,将这种遍历机制抽象为"迭代器对象",可以描述、表示一个元素的位置为遍历"变化中的集合对象",提供一种不变的访问接口。
2.2.1 迭代器的定义
- 基本类型(和指针的定义方法一致)
cpp
int * iter;- 容器类型(以string为例)
cpp
string::iterator iter;2.2.2 迭代器常用函数
begin()
返回值:容器(集合)的首元素的地址基本类型:
cpp
int arr[5] = { 1, 2, 3, 4, 5 };
auto iter = std::begin(arr);容器类型:
cpp
std::string str("abcdefg");
auto iter = str.begin();end()
返回值:容器(集合)的最后一个元素的下一个地址基本类型:
cpp
int arr[5] = { 1, 2, 3, 4, 5 };
auto end_iter = std::end(arr);容器类型:
cpp
std::string str("abcdefg");
auto end_iter = str.end();2.2.3 使用迭代器遍历基本类型的数组
cpp
#include<iostream>
using namespace std;
int main()
{
int arr[5] = { 1, 2, 3, 4, 5 };
// 使用auto自动推断迭代器类型
for (auto iter = std::begin(arr); iter != std::end(arr); iter++)
{
cout << *iter << endl;
}
// 传统指针遍历方式
for (int* p = arr; p < arr + 5; p++)
{
cout << *p << endl;
}
return 0;
}为什么使用迭代器而不使用指针?
- 抽象性和通用性:迭代器提供了一种通用的遍历方式,适用于各种容器
- 安全性和封装性:迭代器隐藏了具体容器的实现细节
- 可迭代性的概念:语法更清晰易读
为什么循环终止条件是 iter != std::end(arr)
因为end()函数返回最后一个有效数字地址的下一个地址("尾后"位置),使用半开区间(左闭右开)表示范围:
- 包括起始位置
- 不包括结束位置
2.2.4 使用迭代器遍历容器(字符串)
cpp
#include<iostream>
using namespace std;
int main()
{
string str("abcdefg");
// 普通迭代器(可修改元素)
for (string::iterator iter = str.begin(); iter != str.end(); iter++)
{
cout << *iter << endl;
// *iter = 'x'; // 可以修改元素
}
return 0;
}常量迭代器
防止修改字符串内容:
cpp
#include<iostream>
using namespace std;
int main()
{
string str("abcdefg");
// 常量迭代器(不可修改元素)
for (string::const_iterator iter = str.cbegin(); iter != str.cend(); iter++)
{
// *iter = 'q'; // 错误:不能修改
cout << *iter << endl;
}
return 0;
}反向迭代器
cpp
#include<iostream>
using namespace std;
int main()
{
string str("abcdefg");
// 反向迭代器(从后往前遍历)
for (string::reverse_iterator iter = str.rbegin(); iter != str.rend(); iter++)
{
cout << *iter << endl; // 输出: g,f,e,d,c,b,a
}
// 常量反向迭代器
for (string::const_reverse_iterator iter = str.crbegin(); iter != str.crend(); iter++)
{
cout << *iter << endl;
}
return 0;
}2.3 使用迭代器操作字符串
erase()删除字符串- 整数参数:删除该位置后面所有字符串
- 迭代器参数:删除当前迭代器位置的字符
cpp
string str = "abc defg";
str.erase(5); // 删除位置5后的所有字符
cout << "str = " << str << endl; // "abc d"
// 使用迭代器删除空格
for (auto it = str.begin(); it != str.end();) {
if (*it == ' ') {
it = str.erase(it); // 删除空格,返回下一个位置的迭代器
}
else {
++it;
}
}
cout << "str = " << str << endl; // "abcdefg"