【从零开始学c++】——string

在这里插入图片描述

一.STL简介(了解)

1.什么是STL

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

2.STL的六大组件

组件名称说明
Container(容器) 各种基本数据结构向量(vector)、双端队列(deque)、列表(list)、集合(set)、多重集合(multiset)、映射(map)和多重映射(multimap),string
Adapter(适配器) 可改变containers、Iterators或Function object接口的一种组件为已有的类提供新的接口,目的是简化、约束、使之安全、隐藏或者改变被修改类提供的服务集合
Algorithm(算法) 各种基本算法如sort、search…等算法Algorithms,用来处理群集内的元素。它们可以出于不同的目的而搜寻、排序、修改、使用那些元素。通过迭代器的协助,我们可以只需编写一次算法,就可以将它应用于任意容器,这是因为所有的容器迭代器都提供一致的接口
Iterator(迭代器) 连接containers和algorithms1.迭代器Iterators,用来在一个对象群集(collection of objects)的元素上进行遍历。这个对象群集或许是个容器,或许是容器的一部分。迭代器的主要好处是,为所有容器提供了一组很小的公共接口。迭代器以++进行累进,以*进行提领,因而它类似于指针
Function object(函数对象)1、一个行为类似函数的对象,它可以没有参数,也可以带有若干参数。2.重载了调用运算符operator()的类的对象都满足函数对象的特征 3、STL中也定义了一些标准的函数对象,如果以功能划分,可以分为算术运算、关系运算、逻辑运算三大类。为了调用这些标准函数对象,需要包含头文件
Allocator(分配器)负责空间配置与管理。从实现的角度来看,配置器是一个实现了动态空间配置、空间管理、空间释放的class template。

3.STL的缺陷

  1. STL库的更新太慢了。这个得严重吐槽,上一版靠谱是C++98,中间的C++03基本一些修订。C++11出
    来已经相隔了13年,STL才进一步更新。
  2. STL现在都没有支持线程安全。并发环境下需要我们自己加锁。且锁的粒度是比较大的。
  3. STL极度的追求效率,导致内部比较复杂。比如类型萃取,迭代器萃取。
  4. STL的使用会有代码膨胀的问题,比如使用vector/vector/vector这样会生成多份代码,当然这是模板语
    法本身导致的。

2.string

1.string的简单了解

1. string是表示字符串的字符串类

  1. string类是basic_string模板类的一个实例,它使用char来实例化basic_string模板类

  2. string在底层实际是: basic_string模板类的别名,typedef basic_string<char, char_traits, allocator>
    string;
    在这里插入图片描述
    在这里插入图片描述

如何对stl的查阅

对stl的学习,我们需要掌握30%左右的接口函数,剩下的接口函数很少用,不需要记住,当我们需要去使用时,再去查阅,那么我们应该怎么去查阅这些接口函数,首先,我们给出两个网站:
一个是c++官网:https://en.cppreference.com/w/,它支持最新的语法,但它的界面比较乱
在这里插入图片描述
另一个是:http://www.cplusplus.com/reference/string/string/string/,它不是官网,它支持c++98和c++11,它的界面比较整洁和规范,容易看,所以推荐使用这个网站去查阅stl。下面我也会介绍怎样去查阅。下面我们以查string为例子:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

然后我们随便点一个接口函数:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

2. string常用接口说明

1.string类 对象常见的构造

在这里插入图片描述
在这里插入图片描述

2.string类对象的容量操作

在这里插入图片描述

void test
{
    string s1("hello world");
    cout << s.size() << endl;//输出11
    cout << s.capacity() << endl;//输出31
	s1.resize(20, 'x');//直接在hello world接9个x,size和capacity都会改变
	s1.resize(5);//只保留前5个字符,但capacity不变
	s1.clear();//将s1中的所有字符全部清空,将size清空为0,不改变capacity的大小

   string s2;
   s2.resize(20;//将s2中的有效字符增加到20个,为20个'\0'

  string s3;
  s3.reserve(20);//将capacity的大小改变为20,不改变size;
}	

总结;

  1. size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一
    致,一般情况下基本都是用size();

  2. clear()只是将string中有效字符清空,不改变底层空间大小。

  3. resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大
    小,如果是将元素个数减少,底层空间总大小不变。

  4. reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于
    string的底层空间总大小时,reserver不会改变容量大小。

3. string类对象的访问及遍历操作

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
总结:
1.[begin(),end()) end()返回的是最后一个字符的下一个位置,c++中凡是给迭代器一般都是给的[)左闭右开的区间。

2.迭代器是类似指针一样的东西,迭代器以++进行累进,以*进行提领。

3.迭代器的意义:像string,vector支持[]遍历,但是list,map等等容器不支持[],迭代器能够使遍历的方式统一

4.迭代器是可读可写。const_iterator const对象 只能读不能写,const对象只能用const_iterator

4. string类对象的修改操作

在这里插入图片描述

void test
{
string s1;
	//尾插一个字符
	s1.push_back('h');
	s1.push_back('e');
	s1.push_back('l');
	s1.push_back('1');
	s1.push_back('o');
	cout << s1 << endl;//输出hello

    //尾插一个字符串
	s1.append("world");
	cout << s1 << endl;//输出helloworld


    //尾插一个字符串
	s1.append(s2);//或者s1.append(s2.begin(), s2.end());
	cout << s1 << endl;//输出helloworld!!!

    //尾插实际喜欢用+=
    s1 += ' ';
	s1 += "sjp";
	s1 += s2;
	cout << s1 << endl;//输出helloworld!!! sjp!!!

   //插入数据
   s1.insert(4," ");//在位置4插入一个空格
	cout << s1 << endl;//输出hello world!!! sjp!!!


   //插入不能越界,例如:
	//s1.insert(300, "yyyy");会报错

   //删除
   	s1.erase(0, 3);//从0位置开始,删除3个
	//s1.erase(0, 1000);//删多了,不会报错,把字符串全部删完
	s1.erase(3);//这个从3的位置后面全部删完
	s1.erase();//这个全部删完

    //假设要求取出文件名的后缀
	string filename1("test.cpp");
	size_t pos1 = filename1.find('.');//如果找不到,则返回npos

	if (pos1 != string::npos)
	{
		string suff(filename, pos1);
		cout << suff << endl;//输出cpp
	}


   string filename2("test.a.cpp");
   size_t pos2=filename2.rfind('.');//从后往前开始找,找不到则返回npos
   if (pos2 != string::npos)
	{
		string suff(filename, pos2);
		cout << suff << endl;//输出cpp
	}

}

获取一个网址的协议名和域名
在这里插入图片描述

string GetProtocol(const string& ur1)//获取协议名
{
	size_t pos = ur1.find("://");//find不仅可以查找字符也可以查找字符串
	if (pos != string::npos)
	{
		return ur1.substr(0, pos);//返回一个从0开始,pos个字符的字串
	}
	else
	{
		return string();//返回一个匿名对象,为空串
	}
}


string GetDomain(const string& ur1)//域名
{
	size_t pos = ur1.find("://");
	if (pos != string::npos)
	{
		size_t start = pos + 3;
		size_t end=ur1.find("/",start);//从start开始找”/"
		if (end != string::npos)
		{
			return ur1.substr(start,end-start);//从start开始截取end-start个字符
		}
		else
		{
			return string();//返回一个匿名对象,为空串
		}

	}
}


int main()
{
	string s1 = "https://daohang.qq.com/?fr=hmpage";
	string s2 = "http://www.cplusplus.com/reference/string/string/string/";
	
	cout<<GetProtocol(s1)<<endl;
	cout<< GetDomain(s1) <<endl;

	cout<<GetProtocol(s2)<<endl;
	cout<<GetDomain(s2)<<endl;

	return 0;
}

输出结果为:
在这里插入图片描述

注意:

  1. 在string尾部追加字符时,s.push_back© / s.append(1, c) / s += 'c’三种的实现方式差不多,一般
    情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。
  2. 对string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留好。
  3. 尽量少用insert,erase,因为底层实现是数组,头部或者中间要挪动数据,效率太低了。

感谢你的点赞和关注,收藏!!!!
在这里插入图片描述

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值