文章目录
- 一、为什么学习string类?
- 1.1 C语言中的字符串
- 二、准库中的string类
- 2.2 string类
- 2.3 string类的常用接口说明
- 2.4 string类对象的容量操作
- 2.5 string类对象的访问及遍历操作
- 2.5 string类对象的修改操作
- 2.7 string类非成员函数
- 2.8 模拟实现string
一、为什么学习string类?
1.1 C语言中的字符串
C语言中,字符串是以’\0’结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。
二、准库中的string类
2.2 string类
string类文档
- string是表示字符串的字符串类
- 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
- string在底层实际是:basic_string模板类的别名,typedef basic_string<char, char_traits, allocator>string;
- 不能操作多字节或者变长字符的序列。
在使用string类时,必须包含#include头文件以及using namespace std;
2.3 string类的常用接口说明
- string类对象的常见构造:文档说明
- 下面就可以这样使用
int main()
{
string s0;
string s1("hello world");
string s2(s1);
string s3(s1, 5, 3);
string s4(s1, 5, 10);
string s5(s1, 5);
cout << s0 << endl;
cout << s1 << endl;
cout << s2 << endl;
cout << s3 << endl;
cout << s4 << endl;
cout << s5 << endl;
string s6(10, '#');
cout << s6 << endl;
s0 = s6;
cout << s0 << endl;
return 0;
}
2.4 string类对象的容量操作
- 可以看下面的概图
- 接下来我们一个一个看看
- size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一 致,一般情况下基本都是用size()。
- max_size()是返回最大存放多少个字符
- 每个平台可能不一样
- 大家可以看这里的测试,第一次是
15
,第二次是2倍扩容,第三次,第四次…都是1.5倍扩容
- 在linux平台下,默认从0开始,后续从2倍扩容
- reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于 string的底层空间总大小时,reserver不会改变容量大小。
- resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字 符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的 元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。
void Teststring3()
{
// 注意:string类对象支持直接用cin和cout进行输入和输出
string s("hello, world!!!");
cout << s.size() << endl;
cout << s.length() << endl;
cout << s.capacity() << endl;
cout << s << endl;
// 将s中的字符串清空,注意清空时只是将size清0,不改变底层空间的大小
s.clear();
cout << s.size() << endl;
cout << s.capacity() << endl;
// 将s中有效字符个数增加到10个,多出位置用'a'进行填充
// “aaaaaaaaaa”
s.resize(10, 'a');
cout << s.size() << endl;
cout << s.capacity() << endl;
// 将s中有效字符个数增加到15个,多出位置用缺省值'\0'进行填充
// "aaaaaaaaaa\0\0\0\0\0"
// 注意此时s中有效字符个数已经增加到15个
s.resize(15);
cout << s.size() << endl;
cout << s.capacity() << endl;
cout << s << endl;
// 将s中有效字符个数缩小到5个
s.resize(5);
cout << s.size() << endl;
cout << s.capacity() << endl;
cout << s << endl;
}
- 判断字符串是否为空
-
将
capacity
缩小适合大小 -
在vs下是缩小到刚刚说的倍数上
- 在Linux下是缩小到size大小
2.5 string类对象的访问及遍历操作
- 对于元素的访问操作我们有四种方式
begin()+end()
for
[]
范围for(C++11支持)
void Teststring7()
{
string s1("hello world");
const string s2("Hello world");
cout << s1 << " " << s2 << endl;
cout << s1[0] << " " << s2[0] << endl;
s1[0] = 'H';
cout << s1 << endl;
// s2[0] = 'h'; 代码编译失败,因为const类型对象不能修改
}
- 以下这些方法都是可以的
void Teststring6()
{
string s("hello world");
// 1. for+operator[]
for (size_t i = 0; i < s.size(); ++i)
cout << s[i] << ' ';
cout << endl;
// 2.迭代器
string::iterator it = s.begin();
while (it != s.end())
{
cout << *it << ' ';
++it;
}
cout << endl;
// string::reverse_iterator rit = s.rbegin();
// C++11之后,直接使用auto定义迭代器,让编译器推到迭代器的类型
auto rit = s.rbegin();
while (rit != s.rend()) {
cout << *rit << ' ';
++rit;
}
cout << endl;
// 3.范围for
for (auto ch : s)
cout << ch << ' ';
cout << endl;
}
2.5 string类对象的修改操作
- c_str和data使用差不多,但是c_str使用较多
- 在比较的时候
==
是用的一个重载,而使用c_str比较是比较地址
- 案例一:
- 找后缀
// 获取file的后缀
string file("string.cpp");
// 从后往前找 '.'
size_t pos = file.rfind('.');
// 截取从pos位置开始到最后
string suffix(file.substr(pos,file.size() - pos));
cout << suffix << endl;
-
案例二:
-
获取url中的协议
-
用find查找
.
,然后再使用substr截取字符串
string url("https://www.cplusplus.com/reference/string/string/find/");
cout << url << endl;
size_t n = url.find(':');
if (n == string::npos)
{
cout << "invalid url" << endl;
return;
}
string protocol = url.substr(0, n);
cout << protocol << endl;
cout << url.substr(0, n) << endl;
- 获取url中的域名
size_t start = url.find("://");
if (start == string::npos)
{
cout << "invalid url" << endl;
return;
}
start += 3; // 跳过 ://
size_t finish = url.find('/', start);
string address = url.substr(start, finish - start);
cout << address << endl;
cout << url.substr(start, finish - start) << endl;
- 删除url的协议前缀
size_t pos = url.find("://");
url.erase(0, pos + 3);
cout << url << endl;
-
find_first_of
-
查找字符串中的包含所有字符
- find_first_not_of
- 后面的last就是从后往前找,很简单,不再赘述
2.7 string类非成员函数
- 这里比较重要的是
getline()
- 这个和C语言中的gets差不多,读一行,读到
\n
后停止 - 这个还多一个功能,就是可以指定读到什么字符后停止
2.8 模拟实现string
- 这个的模拟实现就到下一篇文章来写~~
最后,本文学习了C++中的string类,简单的介绍了几个比常用的几个接口,以及如何使用,感谢收看