【STL】 string类使用一站式攻略

目录

一,STL

1. 简介

2. STL的版本

3. STL 六大组件  

4.  学习STL, 三境界

5. 学会查看C++文档 

二, string类

1. 相对于C语言,我们为什么还需要学习C++的string?

2. 头文件

3.  常见构造函数

4.  operator=   

5.  operator[]  &&  at函数

6. string容量方面

1. 关于  size 与 length  的选择

2. 关于string类 的扩容机制

3.  设置容量

7. iterators——迭代器(重要)

1. 回望 C++入门的 范围 for (语法糖  for)

2. 反向迭代

8. 字符串插入

1. 常见的插入方式:

2. 关于中间插入 insert的使用 

9. 删除字符串——erase

10.  c_str

1. 使用场景

 2. ‘\0’在 C语言  &  C++string类中的区别

11. find & rfind

1.获取文件名后缀

 2. 分离网址

12. getline

13. 字符串 互相转化  其他数据(C++11)

关于string类使用总结

结语


一,STL

1. 简介

STL(standard template libaray-标准模板库):C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架

2. STL的版本

原始版本
Alexander Stepanov Meng Lee 在惠普实验室完成的原始版本,本着开源精神,他们声明允许任何人任意运用、拷贝、修改、传播、商业使用这些代码,无需付费。唯一的条件就是也需要向原始版本一样做开源使用。 HP 版本 -- 所有 STL 实现版本的始祖。
P. J. 版本
P. J. Plauger 开发,继承自 HP 版本,被 Windows Visual C++ 采用,不能公开或修改,缺陷:可读性比较低,
符号命名比较怪异。
RW 版本
Rouge Wage 公司开发,继承自 HP 版本,被 C+ + Builder 采用,不能公开或修改,可读性一般。
SGI 版本
Silicon Graphics Computer Systems Inc 公司开发,继承自 HP 版 本。被 GCC(Linux) 采用,可移植性好,可公开、修改甚至贩卖,从命名风格和编程 风格上看,阅读性非常高。 我们后面学习STL要阅读部分源代码,主要参考的就是这个版本

3. STL 六大组件  

4.  学习STL, 三境界

1. 熟练使用 STL。

2. 能够比较清晰的认识STL的底层原理。

3. 能够编写STL的扩展。(在校期间,少数能掌握)

5. 学会查看C++文档 

  Reference - C++ Reference (cplusplus.com)

学习中光string类就有100来个接口,我们熟练掌握常见20个,其余80来个需要我们查找文档,而最好的方式是查看英文原文档。 

二, string类

1. 相对于C语言,我们为什么还需要学习C++的string?

C语言中,字符串是以'\0'结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可能还会 越界访问

2. 头文件

 使用string类时,必须包含头文件以及using namespace std;

#include <string>

3.  常见构造函数

 常见的string类构造函数及功能:

1.      string() (重点)                              构造空的string类对象,即空字符串
2.      string(const char* s) (重点)       用C-string来构造string类对象
3.      string(size_t n, char c)                   string类对象中包含n个字符c
4.      string(const string&s  ) (重点)     拷贝构造 函数

这是原文:

选择 constructor (函数)进入: 

即可见 

建议:尝试去阅读原文档,对函数功能的解释。

同时,从查看文档可知,string类  重载了  流提取 & 流插入, 我们直接cout , cin

演示如下:

int main()
{
	// string(const char* s) (重点)  用string来构造string类对象
	string s1("hello, C++");
	cout << "s1 :" << s1 << endl;

	// string() (重点)  构造空的string类对象,即空字符串
	string s2;
	cout << "s2 :" << s2;
	cin >> s2;
	cout << "s2 :" << s2 << endl;

	// string(const string & s) (重点) 拷贝构造函数
	string s3(s1);
	cout << "s3 :" << s3 << endl;

	// string(size_t n, char c)   string类对象中包含n个字符c
	string s4(4, 'c');
	cout << "s4 :" << s4 << endl;
	
	return 0;
}

这里单独对第三个函数 子链函数  进行解释:

4.  operator=   

 成员函数:

 功能展示:

int main()
{
	string s2;
	// string & operator= (const char* s);
	string s1 = "hello, C++"; // 构造 + 拷贝 -> 优化为一次构造
	cout << "s1: " << s1 << endl; // 结果: hello, C++

	// string& operator= (const string & str); 
	s2 = s1;
	cout << "s2: " << s2 << endl; // 结果: hello, C++
	
	// string& operator= (char c);
	s2 = 'x';
	cout << "s2: " << s2 << endl; // 结果: x

	return 0;
}

补充: assign 函数 跟赋值差不多,感兴趣可以去查查文档,这里不进行举出。

5.  operator[]  &&  at函数

功能描述: 两者都是使string类像数组一样的访问字符串。

成员函数:

 

区别在返回值 

operator[]  在越界时会发生 断言 ;at 访问越界则 返回 异常

功能展示: 

int main()
{   
	// 1. char& operator[] (size_t pos); // 返回可修改的别名
	string s1 = "hello, C++";
	cout << s1[4] << endl;  // at :  s1.at(4)
	s1[4] = 'k';  // 如果类对象实例化时,未被const修饰,同时也具有修改的能力

	// 2. const char& operator[] (size_t pos) const;
	const string s2 = s1;
	cout << s2[4] << endl;
	s2[4] = 'o'; // s2 被const修饰,不允许修改其内容

	return 0;
}

 6. string容量方面

1. 关于  size 与 length  的选择

两者功能都是获取容器中字符串长度

 一般推荐使用 size() ,因为 length出道比较早,size是后期出道,string类中使用 size 比较多。(注意: max_size 这个没什么意义,返回的都是41亿)

简单遍历输出一遍字符串:

int main()
{   
	string s1 = "hello, C++";
	for (int i = 0; i < s1.size() ; i++)
	{
		cout << s1[i];  // at: s1.at(i);
	}
	return 0;
}

2. 关于string类 的扩容机制

结论: 在不同编译器下扩容机制可能不同,有的是1.5倍,而有的是2倍的扩容。(STL标准库,只是一种标准,不同的编译器厂商有着自己的功能实现方法)

这里用同一段代码在 linux g++和 VS2019 下 扩容的结果:

 

3.  设置容量

我们知道频繁扩容,会有额外的消耗,于是我们预先设定一定大小的容量,减少扩容次数。

函数:

简单使用:

    s1.reserve(1000); // 单纯开空间

	s2.resize(1000);  // 开空间, 同时设置字符,默认为‘0’
	s2.resize(1000, 'c');

7. iterators——迭代器(重要)

迭代器是string 中的内部类类型,功能跟 operator[]差不多,像数组一样的访问数据。但字符串底层是数组,是一段连续的空间,用operator[] 会比较便利。后面我们学习 STL的vector(顺序表), list(链表)后,我们会发现,operator[]在连续存储的数据结构访问还行,但链表,树,迭代器更合适,而且他们用法类似,因此我们同时学习迭代器。(迭代器是容器通用访问方式,用法类似,提前上路

简单用法:

int main()
{
   string s1 = "hello, C++";
	string::iterator it = s1.begin();
	while (it != s1.end()) // != 原因:1. string类本身有关 2.其他容器也是用 != 这样设计统一了 
	{
		cout << *it;
		it++;
	}
	return 0;
}

s1.begin() 和  s1.end() 返回迭代器的位置是   [左闭区间 右开区间)  

1. 回望 C++入门的 范围 for (语法糖  for)

 int main()
{   
    string s1 = "hello, C++";
	for ( auto e : s1) // 自动++, 自动判断结束
	{
		cout << e;
	}
return 0;
}

语法糖  底层是通过 迭代器实现,且只能正向遍历。

2. 反向迭代

功能:反向遍历数据

 简单用法:

int main()
{
    string s1 = "hello, C++";
	string::reverse_iterator it = s1.rbegin(); 
	while ( it != s1.rend())
	{
		cout << *it;
		it++; // 底层肯定是反向++
	}
  return 0;
}

当然 不管是 s1.begin ,s1.end; s1.rbegin, s2.rend都有返回 const 修饰迭代器重载函数(一般发生在 传string引用时,如: const string& s1)

8. 字符串插入

C语言中,库函数strcat 也有这样的功能,但没有C++这么智能,C语言劣势:

  • 1. 每次插入字符,字符串需要遍历整个字符串,效率低,且需要保证被插入的字符数组足够大
  • 2. C++的插入会记录末尾字符下标,可以做到直接插入。

1. 常见的插入方式:

1. push_back

2. append

3. operator += 

详细查文档

简答操作:

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string s1("hello, C++");
	s1.push_back('6');
	s1.push_back('-');
	s1.push_back('-');
	cout << s1 << endl;

	s1.append("5");
	cout << s1 << endl;

	string s2(s1);
	s2 += s1;
	s2 += 'c';
	s2 += "你好";
	cout << s2 << endl;
	return 0;
}

2. 关于中间插入 insert的使用 

结论: 尽量少用,string类,insert 中间插入,会导致后面字符挪位,假设要头插入n个字符,第2次,挪一次; 第3次,挪2次;第n次,挪 n - 1次;所以挪位时间复杂度n2了,所以尽量少用。

常见的三个insert 的使用:

运用如下:

int main()
{
	// 1. 迭代器
	string s1 = "hello, C++";
	string::iterator it = s1.begin() + 2; // 也就是在下标为2的位置插入
	s1.insert(it, 'Z');
	cout << s1 << endl; // heZllo, C++


	string s2 = s1;
	s2.insert(2, "你好"); // 下标为2的位置
	cout << s2 << endl;

	string s3 = s1;
	s3.insert(5, s2);    // 下标为5的位置插入
	cout << s3 << endl;
	return 0;
}

9. 删除字符串——erase

 函数: erase

代码实践: 

int main()
{
	// 1. 迭代器
	string s1 = "hello, C++";
	string::iterator it = s1.begin() + 2; // 也就是在下标为2的位置插入
	s1.insert(it, 'Z');
	cout << s1 << endl; // heZllo, C++


	string s2 = s1;
	s2.insert(2, "你好"); // 下标为2的位置
	cout << s2 << endl;

	string s3 = s1;
	s3.insert(5, s2);    // 下标为5的位置插入
	cout << s3 << endl;

	// 1. 迭代器删除
	//s3.erase(2);
	string::iterator it2 = s3.begin() + 2;
	string::iterator it3 = s3.end();
	s3.erase(it2, it3);
	cout << s3 << endl;
	return 0;
}

10.  c_str

1. 使用场景

在一些需要用到C语言接口时,C语言不支持C++的string类,而c_str 成员函数可以将string类字符串转化为C语言兼容的字符串

如:用C语言访问文件夹

    string s1("Test.cpp");
	const char* file = s1.c_str();
	FILE* myfile = fopen( file, "r"); // 不认string类
	char i = fgetc(myfile);
	while ( i != EOF)
	{
		cout << i;
		i = fgetc(myfile);
	}

 2. ‘\0’在 C语言  &  C++string类中的区别

结论: 

C语言比较重要:  ‘\0’在C语言中,像strcopy, strcat等等字符串接口函数结束大多有 '\0' 作为字符串结尾

C++直接无视: 我们可以将字符串中间任意位置设置为\0,但是在C++中字符串会将\0当成一个正常字符处理打印时会当成空格或者不占位置的字符输出

int main()
{
	string s1("test.cpp");
	s1 += '\0';
	s1 += '\0';
	s1 += '\0';
	s1 += '\0';
	s1 += "test.cpp";
	cout << s1.c_str() << endl; // ‘\0’对于C语言,是字符串结束的标志
	cout << s1 << endl;         //   而在string中,字符串中可以存在,但不发生显示或者是空格。
	
	return 0;
}

11. find & rfind

pos: 开始查找的字符位

n:   匹配的字符序列的长度

1.获取文件名后缀

int main()
{   // 1. 简单文件获取后缀
	string s1("test.cpp");
	size_t i = s1.find('.');
	string tmp;
	if (i != string::npos)
	{
		tmp = s1.substr(i); // 先用获取子串函数
	}
	cout << tmp << endl;

	// 2. 复杂后缀,而只取最后的后缀
	string s2("test.cpp.tar.zip");
	size_t i2 = s2.rfind('.');  // 从后向前寻找
	string tmp2;
	if (i2 != string::npos)
	{
		tmp2 = s2.substr(i2);
	}
	cout << tmp2;
	return 0;
}

 补充一下substr:

 2. 分离网址

int main()
{
	string s1("https://mp.csdn.net/mp_blog/creation/editor/131103529");
	// 1. 协议
	size_t pl = s1.find("://");
	size_t next = pl;
	string protocol = s1.substr(0, pl);
	cout << protocol << endl;
	// 2. 域名
	size_t p2 = s1.find("/", next += 3);
	string rn = s1.substr(next, p2 - next);
	next = p2;
	cout << rn << endl;

	// 3. 资源名
	string way = s1.substr(next);
	cout << way << endl;
	return 0;
}

12. getline

 功能:用于从输入流中读取一行数据,并存储到string对象中。

is:输入流对象。

str:用于存储读取的数据的string对象。

delim:可选参数,表示行结束符,默认为'\n'。(没有空格作为结束符)

 比如牛客这道题:

字符串最后一个单词的长度_牛客题霸_牛客网 (nowcoder.com)

13. 字符串 互相转化  其他数据(C++11)

这个感兴趣可以一个个试。举一个栗子:

stoul :  字符串  转  无符号长整型 

关于string类使用总结

   1. 学会查文档!!!(重要

   2. 可以问chatgpt

   3. 多练则会

结语

本小节就到这里了,感谢小伙伴的浏览,如果有什么建议,欢迎在评论区评论;如果给小伙伴带来一些收获请留下你的小赞,你的点赞和关注将会成为博主创作的动力。

猜你喜欢

转载自blog.csdn.net/qq_72112924/article/details/131103529