文章目录
- 0.前置知识--STL简介
- 1.为什么要学习string类?
- 2.auto关键字和范围for
- 3.string类常用的接口
- 4.小试牛刀--例题
-
- 4.1 [字符串中第一个出现唯一的字符](https://leetcode.cn/problems/first-unique-character-in-a-string/description/)
- 4.2 [反转字符串](https://leetcode.cn/problems/reverse-string/description/)
- 4.3 [仅仅反转字母](https://leetcode.cn/problems/reverse-only-letters/description/)
- 4.4 [字符串相加](https://leetcode.cn/problems/add-strings/description/)
0.前置知识–STL简介
STL(standard template libaray-标准模板库):是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架。
STL的六大组件:
我们之前在数据结构阶段学了很多,包括顺序表、链表、栈、队列、二叉树等等;在之后我们在做算法题时,需要用到哪个数据结构,靠我们手写是不太现实的,C++帮我们封装了很多的容器,本质上他们都是给我们实现好的一个个类,我们直接使用即可。当然我们也要学习他的底层,这是很重要的。
本节我们先来学习一下string类。这里有个小知识点,其实string类是不属于STL里的容器的。因为string类的出现是比容器早很多的,因为需要频繁使用字符串。所以string类在设计的时候,不是设计的很好。
string类的内容大概是这样,有size,也有capacity,当然里面有很多的成员方法。(其实里面也有buffer数组,了解一下)
1.为什么要学习string类?
C语言中,字符串是以’\0’结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。比如说strcpy,我们必须有足够的空间让他来拷贝,他的空间大小是固定的,不想string,他的本质就是一个类,是可以自动扩容的。
2.auto关键字和范围for
2.1 auto关键字
-
使用auto修饰的变量,是具有自动存储器的局部变量,后来这个不重要了。C++11中,标准委员会变废为宝赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。
-
用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&
-
当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。
-
auto不能作为函数的参数,可以做返回值,但是建议谨慎使用
-
auto不能直接用来声明数组
Q:写了类型本来就不费事,还要使用auto干什么?
A:等到后面写容器迭代器的,就会很好用。
2.2 范围for
- 对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此C++11中引入了基于范围的for循环。for循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围,自动迭代,自动取数据,自动判断结束。
- 范围for可以作用到数组和容器对象上进行遍历
- 范围for的底层很简单,容器遍历实际就是替换为迭代器,这个从汇编层也可以看到
示例:
int a[5] = {
1, 2, 3, 4 ,5 };
for (auto x : a)
{
cout << x << ' ';
}
cout << endl;
注意:上面我们写的是auto x : a
其底层是将数组a对应下标的值赋值给x,x只是一个临时拷贝的对象,改变x的值不会影响到数组a,我们若是想改变数组a的值,我们就需要使用引用的概念,示例:
3.string类常用的接口
推荐大家去C++的官网学习对应的接口:https://cplusplus.com/
3.1 string类对象常见的构造
构造函数名称 | 功能说明 |
---|---|
string s | 构造空的string类对象s,即空字符串 |
string(const string& s) | 拷贝构造函数 |
string(const string& str, size_t pos, size_t len = npos) | 从字符串str上,从下标pos开始拷贝npos个字符 |
string(const char* s) | 用C-string来构造string类对象 |
string(size_t n, char c) | string类对象中包含n个字符c |
string (const char* s, size_t n) | 从C-string中拷贝前n个字符 |
注:这里解释一下npos,npos默认值是-1,即拷贝到字符串str的末尾,当npos大于字符串长度时不会报错,会拷贝完这个字符串。npos是一个静态成员变量,他的类型是size_t。
示例:
string s1();//构造一个空的字符串
string s2("hello world!");//用C-string来构造string对象
string s3(s2);//拷贝构造
string s4(s2, 6);//npos默认值是-1
string s5("hello world", 5);//拷贝前五个字符
string s6(5, 'x');
cout << s1 << endl;
cout << s2 << endl;
cout << s3 << endl;
cout << s4 << endl;
cout << s5 << endl;
cout << s6 << endl;
3.2 string类对象的访问
函数名称 | 功能说明 |
---|---|
operator[pos] | 返回pos位置的字符,即下标访问 |
at(pos) | 返回pos位置的字符 |
back() | 返回最后一个元素 |
front() | 返回第一个元素 |
示例:
string s("hello world");
for (int i = 0; i < s.size(); i++)
{
cout << s[i];
}
cout << endl;
for (int i = 0; i < s.size(); i++)
{
cout << s.at(i);
}
cout << endl;
cout << "s.front():" << s.front() << endl;
cout << "s.back():" << s.back() << endl;
Q:使用下标[]和at()有什么区别吗?
A:对于访问字符串,如果越界了的话,[]会直接报错,终止程序运行,而at可以通过抛异常来解决,示例:
对于at()访问越界的字符串,我们只要通过捕异常就可以让程序继续运行。
而通过下标[]来获取越界的字符,会直接终止程序。
3.3 string类对象的遍历–迭代器
通过上面下标的方式也可以遍历字符串,这里我们主要讲解一下通过迭代器来遍历。
Q:既然下标可以遍历,为什么还要使用