c++|STL简介+string类的使用(常用接口)

目录

一、STL简介

1.1STL的版本

 1.2STL六大组件

1.3STL的重要性及缺陷 

二、string类简介

2.1string类了解

2.2为什么学习string类

三、string类使用(常用接口)

3.1string类的成员函数

3.1.1构造函数

3.1.2析构函数

3.1.3“=”运算符重载函数 

3.2迭代器(iterator)+string类对象的访问及遍历

3.2.1 iterator

3.2.2 operator[]

3.2.3 at()

3.2.4 back() && front()

3.2.5 范围for

3.3string类对象的容量操作

3.3.1 size() && length()

3.3.2 capacity() && reserve && resize

3.3.3  empty() && clear()

3.4string类对象的修改操作

3.4.1 push_back  && append && assign && insert

3.4.2 operator+=

3.4.3 c_str()

3.4.4 find+ npos && substr()

3.4.5 erase


一、STL简介

STL(standard template libaray-标准模板库):从表面意思来说,他是c++标准库的重要组成成分,他的组件(接口)是可复用的,管理着数据结构和算法。

1.1STL的版本

  • 原始版本--HP版本(所有STL实现版本的始祖),开源版本,允许任何人使用,但后人如对其修改,也需开源。
  • P.J.版本--继承自HP版本,在 HP 版本的基础上进行了大量的独立创作和投入,形成了新的商业价值,那么他可以根据自己的意愿选择是否收费,并制定自己的授权协议。被Windows Visual C++采用,不能公开或修改,那么必然有一定的缺陷不容易发现,可读性较低。
  • RW版本--继承HP版本,被C++ Builder采用,同样不能修改,可读性较低
  • SGI版本--继承HP版本,被GCC(Linux)采用,开源版本,可移植性好,阅读性非常高。在学习过程中,就可以参照这个版本的源码进行研究。

 1.2STL六大组件

STL有六大组件,通过一张图来展示,要学的第一个组件就是容器,这些容器接口说白了就是管理数据结构,最重要的基础就是string接口,string产生其实比STL还要早,后来才归类进来,学会这一个,就可以贯通各个接口,因为用法都大差不差。

 

1.3STL的重要性及缺陷 

STL在笔试中、面试中占了很重要的一部分,在工作中也会经常使用,在学习STL的过程中,也不能急于求成,先学会怎么用,再去深入了解底层,再扩展。当然在学习过程中也可能遇到以下问题,当然这应该也是STL的缺陷。

1.STL更新慢。

2.STL现在没有只差线程安全。并发环境下需要我们自己加锁。且锁的粒度是比较大的

3.STL极度的追求效率,导致内部比较复杂。比如类型萃取,迭代器萃取

4.STL的使用会有代码膨胀的问题,当然这是模板语法本身导致的。

接下来我们进行学习第一个容器接口string类,并结合所学理解STL的缺陷。

二、string类简介

2.1string类了解

1.string类其实就是一个模板类,typedef过来的,是basic_string模板类的一个实例,用的char来实例化basic_string模板类。

2.管理字符序列的一个类

3.string类有许多接口,这些接口都是用来操作操作字符串

4.这个类独立于所使用的编码来处理字节:如果用来处理多字节或变长字符(如UTF-8)的序列,这个类的所有成员(如长度或大小)以及它的迭代器,将仍然按照字节(而不是实际编码的字符)来操作。

2.2为什么学习string类

其实还是一个原则,string类可以更好的面向对象,string类的接口都是拿来使用就行,不需要过分管理底层如何实现,而C语言就不同了,轮子需要自己造,空间需要自己管理 ,不能出错。

 那么接下来,就进行学习string类的常用接口有哪些,以及如何使用。

三、string类使用(常用接口)

在介绍string类接口前先说明一下接口会出现的npos,他是成员常量,在接口中扮演缺省值成分,size_t为unsigned int,无符号整形的-1,即整形最大值。也就是不传参,默认就是缺省值。其次在使用string类的接口时包含一下头文件#include <string>

static const size_t npos = -1;

3.1string类的成员函数

3.1.1构造函数

default (1)
                             string();
                        默认构造函数,构造空的string类对象,即空字符串
copy (2)
                     string (const string& str);
                                                   拷贝构造函数
substring (3)
    string (const string& str, size_t pos, size_t len = npos);
                   从字符串的 pos 位置取len个字符串来构造string类对象
from c-string (4)
                        string (const char* s);
                                        用c-string来构造string类对象
from sequence (5)
                 string (const char* s, size_t n);
                              从字符串中拷贝前n个字符构造string类对象
fill (6)
                     string (size_t n, char c);
                                        string类对象中包含n个字符c

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string str;//构造空对象,调用默认构造函数
	string s("hello world");//用c-string来构造string类对象
	string s1(5, 'x');//创建5个字符x
	string s2(s1);//s1拷贝给s2
	string s3(s, 5, 3);//从第五个位置,拷贝3个字符给s3
	string s4(s, 2);//从第2个位置,npos为整形最大值,默认拷贝后面所有字符给s4,包括'/0'

	string s5("hello world", 5);//拷贝前5个字符给s5

	cout << s << endl;
	cout << s1 << endl;
	cout << s2 << endl;
	cout << s3 << endl;
	cout << s4 << endl;
	cout << s5 << endl;
	return 0;
}

 运行结果:

3.1.2析构函数

~string():这个基本上不用,编译器会自动调用析构函数,释放对象

3.1.3“=”运算符重载函数 

string (1)
string& operator= (const string& str);
c-string (2)
string& operator= (const char* s);
character (3)
string& operator= (char c);
#include <iostream>
#include <string>
using namespace std;
int main()
{

	string s("hello world");
	string s1 = s;
	string s2 = "hello world";

	//string s3 = 'x';这个不支持,这种构造形式只能是字符串,不能是单个字符
	string s3;
	s3 = 'x';


	cout << s << endl;
	cout << s1 << endl;
	cout << s2 << endl;
	cout << s3 << endl;
	return 0;
}

运行结果:

3.2迭代器(iterator)+string类对象的访问及遍历

迭代器本质上可以是内置类型,如typedef过的指针(例如:typedef char* iterator; typedef const char*  const_iterator),也可以是其他类型(自定义类型),虽然迭代器底层实现方式不同,但在表面上其功能是一样的,当作指针来理解使用。其次,迭代器可以适用所有容器,例如:string、vector、list、stack、queue等

3.2.1 iterator

迭代器的范围对于对象而言是左闭右开:[  ),在字符串当中代表最后一个'/0'位置,并不算是有效字符

迭代器是属于string的类域,所以调用迭代器时,要指明类域,即string::iterator

迭代器作用于的成员函数有8个: begin(),end(),rbegin(),rend(),cbegin(),cend(),crbegin(),crend()。

他作用于的成员函数有各自的重载函数。

①begin + end(作用:正向遍历字符串)

iterator begin():返回指向第一个字符串的迭代器

iterator end():返回指向最后一个字符串下一个位置的迭代器,可以认为指向'/0'
const_iterator begin() const:返回指向第一个字符串的迭代器,但迭代器所指向的内容不能修改
 
const_iterator end() const;返回指向最后一个字符串的迭代器,但迭代器所指向的内容不能修改 

#include <iostream>
#include <string>
using namespace std;
int main()
{

	string s("hello world");
	const string s1("excuse me");
	string::iterator it = s.begin();//指向字符串的第一个位置,返回对象为迭代器
	string::const_iterator it1 = s1.begin(); //返回指向第一个字符串的迭代器,但迭代器所指向的内容不能修改
	while (it != s.end())//遍历
	{
		cout << *it;//迭代器当作指针,进行解引用
		//*it = 'x';可以修改
		++it;
	}
	cout << endl;
	while (it1 != s1.end())//遍历
	{
		cout << *it1;//迭代器当作指针,进行解引用
		//*it = 'x';不能修改
		++it1;
	}
	cout << endl;
	return 0;
}

 

 ②rbegin + rend(作用:反向遍历字符串)

reverse_iterator rbegin():反向迭代器,其功能跟begin相反,返回指向最后一个字符的迭代器

reverse_iterator rend():其功能与end相反,返回指向第一个字符的迭代器

const_reverse_iterator begin() const:返回指向最后一个字符串的迭代器,但迭代器所指向的内容不能修改 
const_reverse_iterator end() const返回指向第一个字符的迭代器,但迭代器所指向的内容不能修改 

#include <iostream>
#include <string>
using namespace std;
int main()
{

	string s("hello world");
	const string s1("excuse me");
	string::reverse_iterator it = s.rbegin();//指向字符串的最后一个位置,返回对象为迭代器
	string::const_reverse_iterator it1 = s1.rbegin(); //返回指向最后一个字符串的迭代器,但迭代器所指向的内容不能修改
	while (it != s.rend())//反向遍历
	{
		cout << *it;//迭代器当作指针,进行解引用
		//*it = 'x';可修改
		++it;
	}
	cout << endl;
	while (it1 != s1.rend())
	{
		cout << *it1;//迭代器当作指针,进行解引用
		//*it1 = 'x';不能修改
		++it1;
	}
	return 0;
}

 

③cbegin + cend  ④crbegin + crend

这两个组合就是说明调用的是const对象的迭代器,当调用的是const对象迭代器时,前缀有符号c和不加c都是一样的。

例如:const s1("hello world"); 定义一个const对象,调用const的迭代器。

string::const_iterator it = s1.cbegin();或者string::const_iterator it1 = s1.begin();

同理另外几个也是一样的,所以这两个组合也没啥特别大的作用。

3.2.2 operator[]

属于string类,运算符[ ]的重载函数,直接由string对象调用访问对象元素。

重载版本:

char& operator[](size_t pos):返回pos位置的字符,由const string类对象调用

const char& operator[](size_t pos) const:返回pos位置的字符,是一个常量引用 ,不能对其修改,且在函数内部不能修改对象的成员变量。


#include <iostream>
#include <string>
using namespace std;
int main()
{
	string s("hello world");
	const string s1("excuse me");

	for (size_t i = 0; i < s.size(); i++)
	{
		cout << s[i];
	}
	cout << endl;
	for (size_t i = 0; i < s1.size(); i++)
	{
		cout << s1[i];
		//s[i] = 'x';不能修改常量引用
	}
	return 0;
}

3.2.3 at()

功能跟operatro[]一样,调用方式不同罢了

重载版本:

char& at(size_t pos);

const char& at(size_t pos) const;

using namespace std;
int main()
{
	string s("hello world");
	const string s1("excuse me");

	for (size_t i = 0; i < s.size(); i++)
	{
		cout << s.at(i);
	}
	cout << endl;
	for (size_t i = 0; i < s1.size(); i++)
	{
		cout << s1.at(i);
		//s[i] = 'x';不能修改常量引用
	}
	return 0;
}

 

3.2.4 back() && front()

分别返回最后一个字符和第一个字符 

重载版本: 

char& back();     const char& back();

char& front();      const char& front();

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string s("hello world");
	const string s1(s);

	cout << s.back() << endl;
	s.back() = '!';//修改最后一个字符
	cout << s.back() << endl;

	cout << s.front() << endl;
	s.front() = '!';//修改第一个字符
	cout << s.front() << endl;

	cout << s1.back() << endl;
	cout << s1.front() << endl;
	return 0;
}

 

3.2.5 范围for

 他的底层其实就是用迭代器来实现的,调用的就是迭代器,只不过在表面上的用法不同而已

形式:

for(auto e :  对象) {}; 或者for(auto& e : 对象) {};

e对象的名称可以随便取,一般用e,auto在类和对像章节讲过,根据赋值对象的类型来推演被赋值对象的类型。如何使用范围for的形式,具体也要看对象中的成员赋值给e时,是否要调用拷贝构造,而造成没必要的浪费。

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string s("hello world");
	const string s1 = "string is easy to learn";
	for (auto e : s)//依次取s中的元素到e中,底层调用的就是迭代器。依次打印e中的内容
	{
		cout << e;
	}
	cout << endl;
	for (auto d : s1)
	{
		cout << d;
	}
}

 

3.3string类对象的容量操作

3.3.1 size() && length()

函数原型:

 size_t size() const;    size_t length() const;

他们两的作用是一样的,都是获取字符串的长度,至于为什么有两个,这是因为历史上的原因,早期是先出来的length函数,但后来如果用length来表示树的大小就不合适,所以又造了个size函数,就是为了更符合表面意义,本质上没区别。

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string s("hello world");
	cout << s.size() << endl;
	cout << s.length() << endl;
	return 0;
}

3.3.2 capacity() && reserve && resize

函数原型:

size_t capacity() const;返回string对象容量的大小。

void reserve(size_t n);对容量进行操作,vs下只能扩容,不能缩容

 void resize(size_t);  void resize(size_t, char c);对_size 和容量和数据的操作,vs下对容量的操作只能扩容

#include <iostream>
#include <string>
using namespace std;
int main()
{

	string s("hello world");
    cout << s.size() << endl;
	cout << s.capacity() << endl;//返回空间总大小,可能比字符串的长度大,可能采用了对齐规则

	s.reserve(30);//扩容
	cout << s.capacity() << endl;

    //n是相对字符串的大小
	//n<resize<capacity,进行尾插数据,若未指定尾插数据默认为0
	s.reserve(20);//vs下reserve不支持缩容,所以还是和前面的容量一样
	s.resize(16, 'y');//剩余的空间都尾插'y'
	cout << s.capacity() << endl;
	cout << s << endl;

	//n>capacity,进行扩容,然后尾插数据
	s.resize(46, 'x');//扩容后多余的空间都尾插'x'
	cout << s.capacity() << endl;
	cout << s << endl;

	//resize<n,删除数据,只取前面resize个数据,此时resize不会缩容,但size大小变了
	s.reserve(30);
	s.resize(5);
	cout << s.capacity() << endl;
	cout << s << endl;
	return 0;
}

3.3.3  empty() && clear()

 函数原型:

bool empty() const;判断字符串是否为空

void char();清空字符串中的内容,变为空串

#include <iostream>
#include <string>
using namespace std;
int main()
{

	string s("hello world");

	cout << s << endl;
	cout << s.empty() << endl;//s不为空
	while (!s.empty())//判断s对象是否为空,不是就清空
	{
		s.clear();
	}
	
	cout << s.empty() << endl;//s为空
	s = 'w';//插入一个字符
	cout << s << endl;
	return 0;
}

3.4string类对象的修改操作

3.4.1 push_back  && append && assign && insert

函数原型:

void push_back(char c);尾插一个字符

 append(部分重载):

string& append (const string& str);追加字符串的拷贝

string& append (const char* s);追加字符串的拷贝

string& append (const char* s, size_t n);追加字符串的前n个字符

string& append (size_t n, char c);追加n个字符c

assign的原型跟append的一样,但它的功能是赋值,而不是追加

insert(部分重载):

string& insert (size_t pos, const string& str); pos位置插入字符串

string& insert (size_t pos, const char* s); pos位置插入字符串

string& insert (size_t pos, const char* s, size_t n);pos位置插入字符串的前n个字符

string& insert (size_t pos, size_t n, char c);pos位置插入n个字符c

void insert (iterator p, size_t n, char c);迭代器位置插入n个字符c

iterator insert (iterator p, char c);迭代器位置插入字符c

#include <iostream>
#include <string>
using namespace std;
int main()
{

	string s;

	s.push_back('h');//尾插字符
	s.push_back('e');
	cout << s << endl;

	s.append("llo");//尾插字符串
	s.append("world", 5);
	cout << s << endl;

	s.assign("excuse me");//赋值
	cout << s << endl;

	string s2;
	string s3 = "world";

	s2.insert(0, "hello");//在0位置插入字符串
	cout << s2 << endl;

	s2.insert(s3.size(), s3);
	cout << s2 << endl;

	s3.insert(0, 1, 'h');//0位置插入1个字符h
	s3.insert(s3.begin() + 1, 1, 'e');//迭代器+1位置插入1个字符e
	s3.insert(s3.begin() + 2, 2, 'l');//迭代器+2位置插入2个字符l
	s3.insert(s3.begin() + 4, 'o');//迭代器+4位置插入字符o
	cout << s3 << endl;
	return 0;
}

3.4.2 operator+=

函数原型(重载):

string& operator+= (const string& str);尾插字符串

string& operator+= (const char* s);尾插字符串

string& operator+= (char c);尾插字符

#include <iostream>
#include <string>
using namespace std;
int main()
{

	string s;
	string s1 = "hello";
	s += s1;//尾插字符串
	s += ' ';//尾插字符空格
	s += "world";
	cout << s << endl;
	return 0;
}

 

3.4.3 c_str()

函数原型:

const char* c_str() const;返回指向数组的指针,该数组包含以空结尾的字符序列(即C字符串),数组中的值跟对象中的值一样。就是获取字符串,以c字符形式返回

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string s1 = "hello";
	
	//const char* str=s1;×
	const char* str = s1.c_str();//✓
	cout << str << endl;
	return 0;
}

 

3.4.4 find+ npos && substr()

函数原型:

find:

size_t find (const string& str, size_t pos = 0) const;在pos位置查询字符串,默认从0开始

size_t find (const char* s, size_t pos = 0) const;在pos位置查询字符串,默认从0开始

size_t find (const char* s, size_t pos, size_t n) const;在pos位置查询字符串的前n个字符

size_t find (char c, size_t pos = 0) const;在pos位置查询字符,默认从0开始

若查询到字符串,则返回字符串的起始位置的下标,否则返回npos;

substr: 

string substr (size_t pos = 0, size_t len = npos) const;pos位置往后取len个字符返回给新对象,默认从0位置开始取。

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string s("test1.cpp hello world");
	string s1("https://leetcode.cn/problems/ba-zi-fu-chuan-zhuan-huan-cheng-zheng-shu-lcof/description/");

	size_t pos1 = s1.find(':');//默认从0位置查询字符
	cout << s1.substr(0, pos1) << endl;;
	size_t pos2 = s1.find("/",pos1+3);//从Pos+3的位置查询字符串
	cout << s1.substr(pos1 + 3, pos2-pos1-3) << endl;//从POS+1位置取POS-POS1+3个字符
	cout << s1.substr(pos2 + 1)<<endl;//默认从0开始取POS2+1个字符
	cout << s.c_str() << endl;
	cout << s.substr(2)<<endl;

	size_t pos3 = s1.find("/");
	while (pos3 != string::npos)
	{
		s1.replace(pos3, 1, "*");//pos3位置,替换一个字符
		pos3 = s1.find("/", pos3 + 1);
	}
	cout << s1 << endl;

	return 0;
}

 运行结果:

3.4.5 erase

string& erase (size_t pos = 0, size_t len = npos);从Pos位置删除len个字符,默认从0开始,默认删除所有字符

iterator erase (iterator p);删除迭代器位置的字符

iterator erase (iterator first, iterator last);删除迭代器区间的字符

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string s("test1.cpp   hello world");
	cout << s << endl;

	s.erase(0,5);//从0位置删除5个字符
	cout << s << endl;

	s.erase(0, 4);//从0位置删除4个字符
	cout << s << endl;

	s.erase(s.begin());//删除迭代器位置
	cout << s << endl;

	s.erase(s.begin(), s.begin() + 2);//删除迭代器区间的字符
	cout << s << endl;
    
    s.erase();
	cout << s << endl;//s为空

	return 0;
}

 

end~

  • 19
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值