C++ 进阶基础之六
大纲
- C++ 进阶基础之一、C++ 进阶基础之二、C++ 进阶基础之三
- C++ 进阶基础之四、C++ 进阶基础之五、C++ 进阶基础之六
- C++ 进阶基础之七、C++ 进阶基础之八、C++ 进阶基础之九
- C++ 进阶基础之十、C++ 进阶基础之十一
string 容器
string 容器的概念
string
是 STL 的字符串类型,通常用来表示字符串。而在使用 string
之前,字符串通常是用 char*
表示的。string
与 char*
都可以用来表示字符串,两者的区别如下:
string
是一个类,char*
是一个指向字符的指针string
封装了char*
来管理字符串,本质是一个char*
类型的容器string
不用考虑内存释放和越界的问题string
负责管理char*
所分配的内存。每一次string
的复制,取值都由string
类负责维护,不用担心复制越界和取值越界等问题string
提供了一系列的字符串操作函数,例如:查找(find)、拷贝(copy)、删除(erase)、替换(replace)、插入(insert)
stirng 容器的 API
string 的构造函数
- 默认构造函数:
string();
- 带参数的构造函数:
string(const char *s);
,用字符串 s 初始化string(int n, char c);
,用n
个字符 c 初始化
- 拷贝构造函数:
string(const string &str);
string 的长度
size_t size() const
,返回当前字符串的长度,这里的长度不包括字符串的结尾的\0
字符size_t length() const;
,返回当前字符串的长度,这里的长度不包括字符串的结尾的\0
字符bool empty() const;
,判断当前字符串是否为空
值得一提的是,sizeof()
返回的是对象所占用空间的字节数,strlen()
返回的是字符数组中第一个 \0
前的字节数,string
的成员函数 size()
和 length()
没有任何区别。
string 的赋值
string &operator=(const string &s);
,把字符串 s 赋给当前的字符串string &assign(const char *s);
,把字符串 s 赋给当前的字符串string &assign(const char *s, int n);
,把字符串 s 的前n
个字符赋给当前的字符串string &assign(const string &s);
,把字符串 s 赋给当前字符串string &assign(int n, char c);
,用n
个字符 c 赋值给当前字符串string &assign(const string &s, int start, int n);
,把字符串 s 中从 start 开始的n
个字符赋值给当前字符串
string 的子串
string substr(int pos=0, int n=npos) const;
,返回由pos
位置开始的n
个字符组成的子字符串
string 的查找
int find(char c, int pos=0) const;
,从pos
位置开始查找字符 c 在当前字符串第一次出现的位置int find(const char *s, int pos=0) const;
,从pos
位置开始查找字符串 s 在当前字符串第一次出现的位置int find(const string &s, int pos=0) const;
,从pos
位置开始查找字符串 s 在当前字符串第一次出现的位置int rfind(char c, int pos=npos) const;
,从pos
位置开始查找字符 c 在当前字符串中最后一次出现的位置int rfind(const char *s, int pos=npos) const;
,从pos
位置开始查找字符串 s 在当前字符串中最后一次出现的位置int rfind(const string &s, int pos=npos) const;
,从pos
位置开始查找字符串 s 在当前字符串中最后一次出现的位置
值得一提的是,当 find()
与 rfind()
函数查找不到时,都会返回 -1
;两者不同的是 find()
是正向查找,而 rfind()
是逆向查找,但是最终两个函数返回的位置均是字符 /
字符串出现的正向位置;若有重复字符 /
字符串时,则 rfind()
返回的是逆向查找到的字符 / 字符串在正向的位置(即最后一次出现的正向位置)。
string 的替换
string &replace(int pos, int n, const char *s);
,删除从pos
位置开始的n
个字符,然后在pos
位置插入字符串 sstring &replace(int pos, int n, const string &s);
,删除从pos
位置开始的n
个字符,然后在pos
位置插入字符串 svoid swap(string &s2);
,交换当前字符串与字符串 s2 的值
string 的比较
int compare(const string &s) const;
,与字符串 s 比较int compare(const char *s) const;
,与字符串 s 比较
compare()
函数的结果在 >
时返回 1,<
时返回 -1,=
时返回 0。字符串比较区分大小写,比较时参考字典顺序,排越前面的越小。大写的 A(65) 比小写的 a(97) 小。
string 的字符存储
char &at(int n);
char &operator[] (int n);
operator[]
和at()
均返回当前字符串中的第n
个字符,但二者是有区别的at()
在越界时会抛出异常,[]
在刚好越界时会返回(char)0
,再继续越界时,程序异常终止- 如果程序希望可以通过
try catch
捕获异常,则建议采用at()
string 的区间插入
string &insert(int pos, const char *s);
,在pos
位置插入字符串 s,返回修改后的字符串string &insert(int pos, const string &s);
,在pos
位置插入字符串 s,返回修改后的字符串string &insert(int pos, int n, char c);
,在pos
位置插入n
个字符 c,返回修改后的字符串
string 的区间删除
string &erase(int pos=0, int n=npos);
,删除从pos
位置开始的n
个字符,返回修改后的字符串
string 的字符串拼接
string &operator+=(const string &s);
,把字符串 s 连接到当前字符串的结尾string &operator+=(const char *s);
,把字符串 s 连接到当前字符串的结尾string &append(const char *s);
,把字符串 s 连接到当前字符串的结尾string &append(const char *s, int n);
,把字符串 s 的前n
个字符连接到当前字符串的结尾string &append(const string &s);
,把字符串 s 连接到当前字符串的结尾string &append(const string &s, int pos, int n);
,把字符串 s 中从pos
位置开始的n
个字符连接到当前字符串的结尾string &append(int n, char c);
,在当前字符串的结尾添加n
个字符 c
从 string 取得 char*
const char *c_str() const;
,返回一个以\0
结尾的字符串的首地址
值得一提的是,char *
可以隐式转换为 string
类型,反过来则不可以,例如右边这种写法是合法的: char *p = "abc"; string str = p;
将 string 拷贝到 char* 指向的内存空间
int copy(char *s, int n, int pos=0) const;
将当前串中以 pos
位置开始的 n
个字符拷贝到以 s
为起始位置的字符数组中,返回实际拷贝的字符数量。特别注意,要保证指针 s
所指向的内存空间足以容纳当前的字符串,不然可能会发生越界。
string 容器的常用操作
- string 容器的构造与赋值
1 |
|
程序运行输出的结果如下:
1 | str1 = 123456 |
- string 容器的 API 调用
1 |
|
程序运行输出的结果如下:
1 | a b c d e |
pair 的使用
pair 的基本概念
pair 是将 2 个数据组合成一组数据,当有这样的需求时就可以使用 pair,如 STL 中的 map 就是将 key 和 value 放在一起来保存。另一个应用是,当一个函数的返回值需要返回 2 个数据的时候,可以选择 pair。 值得一提的是,pair 的实现是一个结构体,主要的两个成员变量是 first
和 second
;因为是使用 struct 不是 class,所以可以直接使用 pair 的成员变量。pair 定义如下:
- 类模板:
template<class T1,class T2> struct pair
- 参数:T1 是第一个值的数据类型,T2 是第二个值的数据类型
- 功能:pair 将一对值 (T1 和 T2) 组合成一个值,这一对值可以具有不同的数据类型
pair 的 API 介绍
1 | p1 < p2; // 两个 pair 对象间的小于运算,其定义遵循字典次序:如 p1.first < p2.first 或者 !(p2.first < p1.first) && (p1.second < p2.second) 则返回 true |
pair 的构造与赋值
pair 的构造函数
1 | pair<T1, T2> p1; // 创建一个空的 pair 对象(使用默认构造函数),它的两个元素分别是 T1 和 T2 类型,采用值初始化。 |
pair 包含两个数值,与容器一样,pair 也是一种模板类型,但是又与之前介绍的容器不同。在创建 pair 对象时,必须提供两个类型名,两个对应的类型名的类型可以不相同。
1 | pair<string, string> anon; // 创建一个空对象 anon,两个元素类型都是 string |
当然也可以在定义时进行成员初始化
1 | pair<string, string> author("James", "Joy"); // 创建一个 author 对象,两个元素类型分别为 string 类型,并默认初始值为 James 和 Joy |
pair 类型的使用相当的繁琐,如果定义多个相同的 pair 类型对象,可以使用 typedef
关键字简化声明
1 | typedef pair<string,string> Author; |
pair 的赋值操作
pair 变量之间的赋值操作如下:
1 | pair<int, double> p1(1, 1.2); |
pair 的常用操作
创建新的 pair 对象
可以调用 make_pair()
函数创建新的 pair 对象。
1 |
|
程序运行输出的结果如下:
1 | name: James, age: 18 |
访问 pair 的两个元素
可以通过 first
和 sencond
访问 pair 中的两个元素。
1 |
|
程序运行输出的结果如下:
1 | 1 2.5 |
通过 tie 获取 pair 元素值
可以通过 tie
获取 pair 元素值。
1 |
|
程序运行输出的结果如下:
1 | name: Sven, age: 25 |