个人主页:@Weraphael
✍作者简介:目前学习C++和算法
✈️专栏:C++航路
希望大家多多支持,咱一起进步!
如果文章对你有帮助的话
欢迎 评论 点赞 收藏 加关注✨
STL
(standard template libaray
- 标准模板库):是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架。
STL的六大组件:
string
是一个管理字符数组的类
该类的接口与常规容器的接口基本相同,再添加了一些专门的函数用来操作string
的常规操作。例如:push_back
等(后面会详细介绍)
string
在底层实际是:basic_string
;模板类的别名:typedef basic_string
在使用string
类时,必须包含头文件#include
string
类对象,即空字符串#include
#include
using namespace std;
int main()
{
// 构造空的string类对象s1
string s1;
cout << "s1的内容为:" << s1 << endl;
return 0;
}
【输出结果】
C
语言的格式字符串来构造string
类对象#include
#include
using namespace std;
int main()
{
// 用C格式字符串构造string类对象s2
string s2("hello world");
cout << "s2的内容为:" << s2 << endl;
return 0;
}
【输出结果】
#include
#include
using namespace std;
int main()
{
// 用C格式字符串构造string类对象s2
string s2("hello world");
// 拷贝构造
string s3(s2);
cout << "s3的内容为:" << s3 << endl;
return 0;
}
【输出结果】
string
类支持赋值运算符重载=#include
#include
using namespace std;
int main()
{
string s1 = "hello world";
cout << s1 << endl;
s1 = "hello China";
cout << s1 << endl;
return 0;
}
【输出结果】
返回字符串的有效长度(不包含
'\0'
)
#include
#include
using namespace std;
int main()
{
string s1("hello world");
int s1_lengrh = s1.size();
cout << "s1的有效长度为:" << s1_lengrh << endl;
return 0;
}
【输出结果】
注意:
'\0’
是标识字符串结束的特殊字符,不算有效字符!
检测字符是否为空字符串。如果是空字符串返回
true
,否则返回false
#include
#include
using namespace std;
int main()
{
string s1;
string s2("hello world");
cout << s1.empty() << endl;
cout << s2.empty() << endl;
return 0;
}
【输出结果】
清空有效字符
clear
#include
#include
using namespace std;
int main()
{
string s2("hello world");
s2.clear();
cout << "s2的内容为:" << s2 << endl;
return 0;
}
【输出结果】
功能:尾插一个字符
#include
#include
using namespace std;
int main()
{
string s1("h");
s1.push_back('i');
cout << s1 << endl;
return 0;
}
【输出结果】
功能:尾插字符串
#include
#include
using namespace std;
int main()
{
string s1("hello ");
s1.append("world");
cout << s1 << endl;
return 0;
}
【输出结果】
既可以尾插一个字符,也能尾插一个字符串。
#include
#include
using namespace std;
int main()
{
string s1("h");
// 尾插一个字符
s1 += 'i';
cout << "s1 = " << s1 << endl;
string s2("hello ");
// 尾插一个字符串
s2 += "world";
cout << "s2 = " << s2 << endl;
return 0;
}
【输出结果】
- 功能:插入字符或者字符串
- 缺点:效率低,特别是头插
【代码示例】
#include
#include
using namespace std;
int main()
{
string s1("world");
// 头插
s1.insert(0, "hello");
cout << s1 << endl;
// 限制插入的个数
string s2("hello");
s2.insert(0, "world", 3);
cout << s2 << endl;
// 配合迭代器
string s3("11111");
// 尾插3个x
s3.insert(s3.begin() + 5, 3, 'x');
cout << s3 << endl;
return 0;
}
【输出结果】
功能:删除某个位置的字符或者字符串
#include
#include
using namespace std;
int main()
{
string s1("hello world");
// 从下标为2往后删除3个字符
s1.erase(2, 3);
cout << s1 << endl;
string s2("hello world");
// 不指定删除的个数,该下标往后全删除
s2.erase(2);
cout << s2 << endl;
//头删
string s3("hello world");
s3.erase(s3.begin());
//尾删
s3.erase(s3.end() - 1);
cout << s3 << endl;
return 0;
}
【输出结果】
功能:交换
#include
#include
using namespace std;
int main()
{
string s1("hello");
string s2("world");
s1.swap(s2);
cout << "s1 = " << s1 << endl;
cout << "s2 = " << s2 << endl;
return 0;
}
【输出结果】
功能:将
string
转化为C字符串。
比如printf
只能打印内置类型,如果想打印string
类型,需要使用c_str
#include
#include
using namespace std;
int main()
{
string s1("hello world");
printf("%s\n", s1.c_str());
return 0;
}
【输出结果】
功能:查找字符。找到第一次出现的字符下标,如果没有找到会返回
npos
,本质就是-1
。
#include
#include
using namespace std;
int main()
{
string s1("hello world");
int pos = s1.find("o");
cout << "第一次出现的位置:" << pos << endl;
// 还可以指定查找的起始位置
pos = s1.find("o", 6);
cout << "第二次出现的位置:" << pos << endl;
return 0;
}
【输出结果】
功能:尾删一个字符
#include
#include
using namespace std;
int main()
{
string s1("hello world");
s1.pop_back();
cout << s1 << endl;
return 0;
}
【输出结果】
功能:截取子串
#include
#include
using namespace std;
int main()
{
string s1("hello world");
// 从下标为0开始往后截取长度为5的子串
cout << s1.substr(0, 5) << endl;
// 如果没有第二个参数,默认截到尾
cout << s1.substr(0) << endl;
return 0;
}
【输出结果】
功能:从字符串的后面开始往前找第一次出现的字符
#include
#include
using namespace std;
int main()
{
string s1("hello world");
int pos = s1.rfind('o');
cout << pos << endl;
return 0;
}
【输出结果】
string
类重载了运算符+
,可以拼接2个字符串
#include
#include
using namespace std;
int main()
{
string s1("hello ");
string s2("world");
string s3 = s1 + s2;
cout << s3 << endl;
return 0;
}
【输出结果】
现阶段可以理解迭代器是像指针一样的类型,但也有可能是指针,也有可能不是指针。
string
迭代器的语法形式:
// string::iterator是类型
// it是变量名
string::iterator it = xxx;
【文档描述】
【代码演示】
#include
#include
using namespace std;
int main()
{
string s1("hello world");
// 返回的是指向字符串的第一个字符
string::iterator it = s1.begin();
// 迭代器是像指针一样的类型
// 因此解引用就可以访问第一个字符
cout << *it << endl;
return 0;
}
【程序结果】
【文档描述】
【代码示例】
#include
#include
using namespace std;
int main()
{
string s1("hello world");
string::iterator it = s1.end() - 1;
cout << *it << endl;
return 0;
}
【输出结果】
【文档描述】
【代码示例】
#include
#include
using namespace std;
int main()
{
string s1("hello world");
string::reverse_iterator rit = s1.rbegin();
while (rit != s1.rend())
{
cout << *rit;
rit++;
}
cout << endl;
return 0;
}
【输出结果】
注:如果觉得
string::reverse_iterator
太长,可以使用auto
代替。
注:
const
修饰的对象不能用普通迭代器
看看以下代码
#include
#include
using namespace std;
void print(const string& s)
{
string::iterator sit = s.begin();
while (sit != s.end())
{
cout << *sit;
sit++;
}
cout << endl;
}
int main()
{
string s1("hello world");
//封装print函数来打印
print(s1);
return 0;
}
【错误报告】
const
修饰的对象只能用const
的迭代器
【正确代码】
#include
#include
using namespace std;
void print(const string& s)
{
string::const_iterator sit = s.begin();
while (sit != s.end())
{
cout << *sit;
sit++;
}
cout << endl;
}
int main()
{
string s1("hello world");
//封装print函数来打印
print(s1);
return 0;
}
【输出结果】
因为
string
底层是支持流提取>>
,用cout
就可以直接打印string
字符串的内容,但是打印的结果比较固定。因此以下三种方式既可以访问遍历,也可以对其内容修改打印。
相当于数组下标的访问
#include
#include
using namespace std;
int main()
{
string s2("hello world");
for (int i = 0; i < s2.size(); i++)
{
// 遍历string字符串
cout << s2[i];
}
cout << endl;
return 0;
}
【输出结果】
当然还可以对字符串进行修改
以下是将字符串的内容都+1
#include
#include
using namespace std;
int main()
{
string s2("hello world");
// 修改
for (int i = 0; i < s2.size(); i++)
{
s2[i]++;
}
// 输出
for (int i = 0; i < s2.size(); i++)
{
cout << s2[i];
}
cout << endl;
return 0;
}
【输出结果】
注意:这里需要区分
string
和普通数组char ch1[] = "abcdef"; ch1[0];// 访问下标为0的元素
ch1[0]
的底层含义是:*(ch1 + 0)
#include
#include
using namespace std;
int main()
{
string s1("hello world");
string::iterator it = s1.begin();
while (it != s1.end())
{
cout << *it;
it++;
}
cout << endl;
return 0;
}
【程序结果】
当然也可以对字符串的内容进行修改
#include
#include
using namespace std;
int main()
{
string s1("hello world");
string::iterator it = s1.begin();
while (it != s1.end())
{
(*it)++;
it++;
}
it = s1.begin();
while (it != s1.end())
{
cout << *it;
it++;
}
cout << endl;
return 0;
}
【输出结果】
在这里就有的人想,迭代器的代码要写这么多,还不如用下标来访问。所以,迭代器的意义是什么呢? 让我们接着往下看
#include
#include
using namespace std;
int main()
{
string s1("hello world");
for (auto x : s1)
{
cout << x;
}
cout << endl;
return 0;
}
【输出结果】
范围for
同样支持修改
#include
#include
using namespace std;
int main()
{
string s1("hello world");
// 修改
for (auto& x : s1)
{
x++;
}
// 输出结果
for (auto x : s1)
{
cout << x;
}
cout << endl;
return 0;
}
【输出结果】
范围
for
虽然很香,但是有个致命的缺点:**不能倒着遍历,只有反向迭代器可以倒着遍历。 **
范围for又和迭代器有啥关系呢?迭代器的意义又是什么呢?
for
代码短,之所以是这么好用是因为:范围for的底层就是用迭代器实现的!!!我们可以利用反汇编来看看代码底层:
范围for
的底层就是调用了begin
和end
。
以下以vector
容器为例
#include
#include
using namespace std;
int main()
{
vector<int> v;
// 尾插数据
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
// 迭代器
vector<int>::iterator vit = v.begin();
while (vit != v.end())
{
cout << *vit << ' ';
vit++;
}
cout << endl;
// 范围for
for (auto e : v)
{
cout << e << ' ';
}
cout << endl;
return 0;
}
【输出结果】
如果一个容器支持迭代器,那么它必定支持访问
for
,反之就不一定了。
这里再提一嘴,很多人认为下标访问是主流,但是使用下标访问的空间必须是连续的,所以当我拿出链表,阁下又该如何应对呢?因此迭代器是可以访问链表的。
这里给大家介绍一个浅浅介绍一个算法(后序会补充),-- sort
【文档描述】
【代码演示】
#include
#include
#include // 算法库头文件
using namespace std;
int main()
{
vector<int> v;
// 尾插数据
v.push_back(10);
v.push_back(3);
v.push_back(2);
v.push_back(5);
// 迭代器
cout << "sort前:";
for (auto x : v)
{
cout << x << ' ';
}
cout << endl;
sort(v.begin(), v.end());
// 迭代器打印sort后的结果
cout << "sort后:";
vector<int>::iterator vit = v.begin();
while (vit != v.end())
{
cout << *vit << ' ';
vit++;
}
cout << endl;
return 0;
}
【程序结果】
注意:cin
和scanf
读取到空格或者回车就不再往后读取了
#include
#include
using namespace std;
int main()
{
string s1;
// 输入
cin >> s1;
// 输出
cout << s1 << endl;
return 0;
}
【输出结果】
而getline
可以读入空格
#include
#include
using namespace std;
int main()
{
string s1;
// 输入
getline(cin, s1);
// 输出
cout << s1 << endl;
return 0;
}
【输出结果】
因为
string
类重载了流插入<<
和流提取>>
,因此可以支持cin
和cout
的输入输出。除此之外还能用puts
来输出string
类的字符串(自带换行的)。注意:puts
和printf
只能打印内置类型的字符串,因此可以用c_str
转化为C语言的字符串
#include
#include
using namespace std;
int main()
{
string s1("hello world");
puts(s1.c_str());
return 0;
}
【输出结果】
#include
#include
using namespace std;
int main()
{
// 转整型
int convert1 = stoi("1111111");
double convert2 = stod("3.14");
float convert3 = stof("6.66");
cout << convert1 << endl;
cout << convert2 << endl;
cout << convert3 << endl;
return 0;
}
【输出结果】
#include
#include
using namespace std;
int main()
{
// 整型转string
string s1 = to_string(1111);
// double转string
string s2 = to_string(3.14);
return 0;
}
【输出结果】