⭐本篇重点:string类的使用
⭐本篇代码:c++学习/05.string类的学习 · 橘子真甜/c++-learning-of-yzc - 码云 - 开源中国 (gitee.com)
目录
一. C/C++字符与string类
二. STL中的string类的使用
2.1 string类常见的构造与赋值
2.2 string对象的数据容量操作
2.3 string对象的遍历和访问操作(读写操作)
operator []访问和范围for
迭代器访问
2.4 string的修改操作
a 插入删除操作 *
b 函数c_str
c 函数find和函数substr
三. string的简单应用-分离网站的协议/域名/资源
四. 下盘文章:string类的模拟实现
一. C/C++字符与string类
我们知道,C语言提供的字符串都是以'\0'为结尾的,在C语言中,库函数给我们提供了很多字符串函数,比如strlen(计算长度), strcmp(比较字符), strcpy(字符串拷贝), strstr(判断是否有子串), strcat(字符串追加)。这些函数可以帮助我们方便的管理字符串。
但是在C++中,这些库函数和类分离,不符合OOP思想。并且字符串的底层需要我们自己去管理,容易越界。
为了更方便的管理和操作字符串,C++ STL为我们提供了string类。string类为我们提供了更为丰富的接口和操作提供我们使用
二. STL中的string类的使用
我们可以在这个文档中查找string类的信息:string文件介绍
//使用string所需头文件
#include <string>
//string包含在std命名空间中
2.1 string类常见的构造与赋值
常见构造方式如下表
构造方式 | 解释 |
string() | 构造空的string类对象,即空字符串 |
string(const string&s) | 拷贝构造函数 |
string(const string&s, size_t pos, size_t len = npos) | 从另一个string对象 pos位置后一个字符开始拷贝,拷贝n个字符 如果没指定n,默认拷贝到结尾 |
string(const char* s) | 用C语言字符串构造一个string对象 |
string(size_t n, char c) | 构造一个含n个c字符的string对象 |
string(const char* s, size_t n) | 构造一个string对象,包含s的前n个字符 |
测试代码如下:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s1; //定义一个string空对象
string s2("hello world!"); //应该为 "hello world"
string s3(s2); //应该为 "hello world"
string s4(s2, 2); //应该是"llo world!"
string s5(5, 'a'); //应该是"aaaaa"
string s6("123456", 4); //应该是"1234"
cout << s1 << endl;
cout << s2 << endl;
cout << s3 << endl;
cout << s4 << endl;
cout << s5 << endl;
cout << s6 << endl;
return 0;
}
运行结果如下:
赋值方法如下
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s1 = "hello world";
string s2 = s1;
string s3;
s3 = s1;
cout << s1 << endl << s2 << endl << s3 << endl;
return 0;
}
2.2 string对象的数据容量操作
string类中给我们提供了很多函数接口
函数名称 | 功能介绍 | |
size() | 返回这个字符串的有效元素长度 | |
length() | 返回这个字符串的有效字符长度(这个和size功能一样) | |
capacity() | 返回字符串空间的大小 | |
empty() | 判断string对象是否为空 | |
clear() | 清空一个string对象,置空。不会改变底层容量 | |
resize(size_t n) resiize(size_t, char c) | 将有效字符变为n个,多余空间是空字符,空间不够会扩容 将有效字符变为n个,多出的空间置为字符c。空间不够会扩容 如果是减少字符,不会减少底层空间 | |
reverse(size_t n = 0) | 为字符串预留n个空间。实际上,编译器会给我们提供的空间会大于n。防止越界访问的问题。 如果n小于当前容量,不会减少容量 |
测试代码1
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s1 = "hello world!";
cout << "s1的有效字符" << s1.size() << endl;
cout << "s1的长度" << s1.length() << endl;
cout << "s1的最大容量" << s1.capacity() << endl;
if (s1.empty())
cout << "s1为空" << endl;
else
cout << "s1为不为空" << endl;
s1.clear();//清空有效字符,清空字符不会更改其最大容量
cout << "s1的有效字符" << s1.size() << endl;
cout << "s1的最大容量" << s1.capacity() << endl;
return 0;
}
运行结果如下:
测试代码2:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s1; "hello world!";
cout << "s1的最大容量" << s1.capacity() << endl;
s1.reserve(100);//将容量设置为100,不修改里面的内容1
cout << "s1的最大容量" << s1.capacity() << endl;
s1.reserve(250); // 实际设置的空间大于250
cout << "s1的最大容量" << s1.capacity() << endl;
string s2;
s2.resize(100); //resize也会扩容
string s3;
s3.resize(100, '$');
cout << s2 << endl;
cout << s3 << endl;
return 0;
}
2.3 string对象的遍历和访问操作(读写操作)
1 可以直接使用cout输出
2 可以使用类似数组的[]进行访问
3 使用迭代器访问
3 范围for
operator []访问和范围for
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s1 = "0123456789";
//1 直接输出
cout << s1 << endl;
//2 使用类似数组的[]遍历访问,也能够修改
//遍历
for (int i = 0; i < s1.size(); i++)
{
cout << s1[i] << " ";
}
cout << endl;
//修改
for (int i = 0; i < s1.size(); i++)
{
s1[i] += 1;
}
//3.使用范围for
for (const auto& c : s1)
{
cout << c << " ";
}
cout << endl;
return 0;
}
运行结果如下
迭代器访问
迭代器访问可以分为正向迭代器访问和逆向迭代器访问。
测试代码:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s1 = "0123456789";
//正向迭代器,string::iterator表示的是string类的迭代器
string::iterator sit = s1.begin();
while (sit != s1.end())
{
//解引用一个迭代器,即可找到这个位置的元素,可以访问和修改这个元素
cout << *sit << " ";
sit++;
}
cout << endl;
//反向迭代器,可以逆向访问和修改容器元素
string::reverse_iterator rsit = s1.rbegin();
while (rsit != s1.rend())
{
cout << *rsit << " ";
rsit++;
}
cout << endl;
return 0;
}
测试结果如下:
2.4 string的修改操作
a 插入删除操作 *
函数 | 说明 |
push_back(char c) | 在字符串结尾插入字符c |
append | 在字符串结尾追加一个字符串 |
operator+= operator-= | 在字符串结尾追加一个字符/字符串 在字符串结尾删除一个字符/字符串 |
insert(size_t pos, const string& s) erase(size_t pos, size_t len = npos) | 在pos位置后面插入字符或者字符串 在pos位置删除n个字符,默认删除到结尾 |
operator + | 同理可以在结尾加上一个字符/字符串。但是这个没有使用引用 效率没有+=高 |
一般建议使用+=这个重载,简单实用且效率较高
测试代码如下
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s1;
s1 += '1'; //1
s1 += "23"; //123
s1.append("45"); //12345
s1.push_back('6'); //123456
cout << s1 << endl;
string s2;
s2.insert(s2.begin(), '0'); //0
s2.insert(0, "1234"); //12340
cout << s2 << endl;
s2.erase(2); //12
cout << s2 << endl;
return 0;
}
b 函数c_str
该函数用于将string类转换成为一个C式字符串
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s1 = "hello world!";
const char* s2 = s1.c_str();
cout << s2 << endl;
return 0;
}
c 函数find和函数substr
find用于查找字符,函数原型如下,C式字符串,string对象,单个字符都能找
找到后返回其起始下标
找不到返回npos
size_t find (char c, size_t pos = 0) const
size_t find (const char* s, size_t pos = 0) const
size_t find (const string& str, size_t pos = 0)
还有 rfind用于从pos位置开始向前查找(用法find一样)
测试代码如下:
#include <iostream>
#include <string>
using namespace std;
int main()
{
//find
string s1 = "123456@qq.com";
string s2 = "qq";
size_t pos1 = s1.find('@'); //单个字符c
size_t pos2 = s1.find('.'); //单个字符c
size_t pos3 = s1.find("com"); //C字符串
size_t pos4 = s1.find(s2); //string对象
size_t pos5 = s1.find("yzc"); //找不到
cout << "pos1:" << pos1 << endl;
cout << "pos2:" << pos2 << endl;
cout << "pos3:" << pos3 << endl;
cout << "pos4:" << pos4 << endl;
cout << "pos5:" << pos5 << endl;
return 0;
}
运行结果
substr用于取字串
函数原型如下:从pos开始取字串(默认0位置),如果len没有指定,默认从pos位置取到结尾处
string substr (size_t pos = 0, size_t len = npos) const;
测试代码
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s1 = "123456@qq.com";
size_t pos1 = s1.find('@'); //单个字符c
size_t pos2 = s1.find('.'); //单个字符c
//substr获取pos位置后的子串
string s2 = s1.substr(pos1);
string s3 = s1.substr(pos2);
cout << "s2:" << s2 << endl; //结果应该为 @qq.com
cout << "s3:" << s3 << endl; //结果应该为 .com
//可以连续获取子串,我们想要获取456
string s4 = "123@456@789";
size_t pos3 = s4.find('@');
cout << s4.substr(pos3) << endl; //获取@456@789
int len = s4.substr(pos3 + 1).find('@'); //计算4到下一个@之间的长度
string ans = s4.substr(pos3 + 1, len);
cout << ans << endl; //应该为456
return 0;
}
测试结果
三. string的简单应用-分离网站的协议/域名/资源
我们使用string分离网站的 协议,域名,资源
比如我的gitte 网站:橘子真甜 (yzc-YZC) - Gitee.com
#include <iostream>
#include <string>
using namespace std;
void Test(const string& url)
{
cout << "网站" << url << endl;
// 1.分离协议 找到':' 那么0到这个位置就是网站的协议
size_t index1 = url.find(':');
if (index1 != string::npos)
{
cout << "协议:" << url.substr(0, index1) << endl;;
}
//分离域名 找到第一个'/',':'+3 和'/'之间的就是域名
size_t index2 = url.find('/', index1 + 3);
if (index2 != string::npos)
{
cout << "域名:" << url.substr(index1 + 3, index2 - (index1 + 3)) << endl;
}
//分离资源 第一个'/'后面的内容就是资源
cout << "资源:" << url.substr(index2 + 1) << endl << endl;
}
//分离网站
int main()
{
//我们知道网站可以分为3部分,实用string类可以将这3部分分离
//1 协议 2 域名 3资源
string url1 = "https://gitee.com/yzc-YZC";
//协议 https 域名 gitee.com 资源 yzc-YZC
Test(url1);
string url2 = "https://mp.csdn.net/mp_blog/creation/editor/143991873?spm=1001.2014.3001.4503";
Test(url2);
return 0;
}
运行结果如下: