STL与string类的认识及简单使用

一、STL

STL(standard template libaray-标准模板库):是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架。
这里仅仅是简单介绍一下STL六大组件,后面结合实例细细分析
在这里插入图片描述

二、string类

使用文档
string从功能上来说属于STL容器,但是从发展历史上来讲,并不是。本文我们只讲述string(utf-8):编码以一个字节为准
在这里插入图片描述
string属于类模板,它的基本结构参考以下代码:

//动态增长字符数组
template <class T>
class basic_string
{
    
    
private:
	T* _str;
	size_t _size;
	size_t _capacity;
};
typedef basic_string<char> string;

构造函数

在这里插入图片描述

void test1()
{
    
    
	//无参构造,空字符串
	string s1;
	//带参构造
	string s2("我在学习string");
	//隐式构造+拷贝构造
	string s3 = "我在学习string";

	string s4(10,'#');
	cout << s1 << endl;
	cout << s2 << endl;
	cout << s3 << endl;

	cout << s4 << endl;
	string s5(s3);
	string s6 = s3;
	cout << s5 << endl;
	cout << s6 << endl;

	string s7("hello world", 5);
	cout << s7 << endl;
	//s7->hello
	string s8(s7, 2, 3);
	cout << s8 << endl;
	//llo
	string s9(s7, 2, 30);
	cout << s9 << endl;
	//llo
	string s10(s7, 2);
	cout << s10 << endl;
	//llo
}

npos是-1,但是这里是无符号,实际并不是-1,是4294967295。
对于s9很明显s7(hello),长度没有30个字符;那么默认就会以str末尾之前的字符进行构造

string类对象可支持直接用cin和cout进行输入和输出,这是因为重载了流插入>>和流提取<<操作符

容量操作

函数名称 功能说明
size(重点) 返回字符串有效字符长度
length 返回字符串有效字符长度
capacity 返回空间总大小
empty (重点) 检测字符串释放为空串,是返回true,否则返回false
clear (重点) 清空有效字符
reserve (重点) 为字符串预留空间
resize (重点) 将有效字符的个数该成n个,多出的空间用字符c填充
void test5()
{
    
    
	//reserve测试
	//TestPushBack();
	

	//resize  将有效字符的个数修改成n个,多出的空间用字符c填充
	string s1("www.ahao.com");
	s1.resize(3);//删除数据
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	cout << s1 << endl << endl;

	string s2("www.ahao.com");
	s2.resize(15,'n');//不扩容增加数据
	cout << s2.size() << endl;
	cout << s2.capacity() << endl;
	cout << s2 << endl << endl;

	string s3("www.ahao.com");
	s3.resize(18,'c');//扩容+插入
	cout << s3.size() << endl;
	cout << s3.capacity() << endl;
	cout << s3 << endl << endl;

}

在这里插入图片描述

size()和length()两个接口底层是完全一样的

  1. size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()。
  2. clear()只是将string中有效字符清空,不改变底层空间大小。
  3. resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。
  4. reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserver不会改变容量大小

扩容问题:

void TestPushBack()
{
    
    
	string s;
	//为字符串预留500字节的空间
	s.reserve(500);
	size_t sz = s.capacity();
	cout << "capacity changed: " << sz << '\n';
	cout << s.size() << endl;
	cout << "making s grow:\n";
	for (int i = 0; i < 1000; ++i)
	{
    
    
		s.push_back('c');
		if (sz != s.capacity())
		{
    
    
			sz = s.capacity();
			cout << "capacity changed: " << sz << '\n';
		}
	}
}

不同平台下扩容规则不同,windows下vs2019是1.5倍扩容;linux下是2倍扩容
扩容也会有开销,如果我们提前知道需要多少空间,就可以使用reserve(n)开好空间

访问及遍历操作

函数名称 功能说明
operator[] 返回pos位置的字符,const string类对象调用
begin+ end begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器
rbegin + rend begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器
范围for C++11支持更简洁的范围for的新遍历方式
void test2()//字符串遍历
{
    
    
	string s1("1234");
	// 遍历他
	cout << s1.size() << endl;
	// 1、下标 []
	for (size_t i = 0; i < s1.size(); ++i)
	{
    
    
		s1[i]++;
	}
	cout << s1 << endl;

	// 2、范围for
	for (auto& ch : s1)
	{
    
    
		ch--;
	}
	cout << s1 << endl;

	//3.迭代器 ----通用的访问形式
	//it1可以理解成一个指针,指向字符串第一个元素的位置
	string::iterator it1 = s1.begin();
	//s1.end()返回有效数据的下一个位置
	while (it1 != s1.end())
	{
    
    
		*it1 += 1;
		++it1;
	}
	it1 = s1.begin();
	while (it1 != s1.end())
	{
    
    
		cout << *it1 << endl;
		++it1;
	}
}

迭代器

迭代器行为上像指针,但是却不一定是指针。
迭代器的意义在于通用,所有容器都可以使用迭代器这种方式去进行遍历和修改。
在这里插入图片描述
正向迭代器:begin+ end与反向迭代器rbegin+rend
在这里插入图片描述
rebegin()返回指向字符串最后一个字符(即其反向开头)的反向迭代器。
rend()返回一个反向迭代器,该迭代器指向字符串第一个字符(被视为其反向结尾)之前的理论元素。
反向迭代器向后迭代:增加它们会将它们移动到字符串的开头。

void test3()
{
    
    
	string s1("1234");
	//不加const
	string::iterator it1 = s1.begin();
	//auto it1=s1.begin();
	while (it1 != s1.end())
	{
    
    
		cout << *it1 << " ";
		++it1;
	}
	cout << endl;
	//反向迭代器
	string::reverse_iterator rit1 = s1.rbegin();
	while (rit1 != s1.rend())
	{
    
    
		cout << *rit1 << " ";
		++rit1;
	}
	cout << endl;
}

在这里插入图片描述
const迭代器
普通的迭代器可读可写,而const迭代器可读不可写,因为const修饰this指向的内容,不能改变

// 正向  反向 -- 可以遍历读写容器数据
// const正向  const反向   -- 只能遍历,不能修改容器数据
void Print(const string& s)
{
    
    
	//遍历读,不能写
	//string::const_iterator it = s.begin();
	//const string::iterator it = s.begin();错误!这里保护的是it本身,即it不能++,但是数据可以变
	auto it=s.begin();
	while (it != s.end() )
	{
    
    
		//*it += 1;不能改变内容

		cout << *it << endl;
		++it;
	}
	cout << endl;
	//反向
	string::const_reverse_iterator rit = s.rbegin();
	//auto rit = s.rbegin();
	while (rit != s.rend())
	{
    
    
		
		cout << *rit << endl;
		++rit;
	}
}

c++11为了区别了普通迭代器和const迭代器提供了四个新的迭代器,本质和begin的const版本一样
在这里插入图片描述

修改操作

函数名称 功能说明
push_back 在字符串后尾插字符c
append 在字符串后追加一个字符串
operator+=(最好用) 在字符串后追加字符串str
c_str 返回C格式字符串
find + npos 从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置
rfind 从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置
substr 在str中从pos位置开始,截取n个字符,然后将其返回
assign 为字符串分配一个新值,替换其当前内容
void test6()
{
    
    
	string s1("www.ahao.com");
	s1 += ' ';
	s1 += '!';
	s1 += "hello world";
	cout << s1 << endl;

	string s2("!!!!!!!");
	s1 += s2;
	cout << s1 << endl;
}

在这里插入图片描述

void test7()
{
    
    
	string s("www.aho.com");

	s.insert(0,"https/");//指定位置插入
	cout << s << endl;

	s.insert(6,"S");
	cout << s << endl;

	s.erase(0,6);//指定位置删除
	cout << s << endl;
	s.erase(3);
	cout << s << endl;

	string s1("hello world hello world");
	string s2("hello world hello world");
	string s3(s2);
	string s4(s3);

	s1.assign("www bbbb",5);  //清空原来的,赋值替换
	cout << s1 << endl;//www b

	s2.replace(6, 3, "wmh");//从6开始替换三个字符
	cout << s2 << endl;//hello wmhld hello world

	// 将' '替换成空格
	size_t pos = s3.find(' ');
	while (pos != string::npos)
	{
    
    
		s3.replace(pos, 1, "20%");
		pos = s3.find(' ', pos + 3);
	}
	cout << s3 << endl;
	
//查看文件内容:文件名不支持c++类型的字符串,只能转换成c类型的
	string file("test.cpp");
	FILE* f = fopen(file.c_str(),"r");//返回string 底层的char* 指针
	assert(f);

	char ch = fgetc(f);
	while (ch != EOF)
	{
    
    
		cout << ch;
		ch = fgetc(f);
	}
	fclose(f);


	string file;
	cin >> file;
	//取文件名后缀 test.cpp 或 test.tat.ccr.bat
	
	//size_t pos = file.find('.');//从前往后找第一个“.”的位置
	size_t pos = file.rfind('.');//从后往前找第一个“.”的位置下标

	if (pos != string::npos)
	{
    
    
		cout << pos << endl;
		string str = file.substr(pos);//返回pos及其位置之后的字符串
		cout << str << endl;
	}

}

非成员函数重载

关系运算符重载

在这里插入图片描述

void test8()
{
    
    
	string str("aaaaa");
	const char* s = "bbbbbbb";

	str == s;//bool operator== (const string & lhs, const char* rhs);
	
	s == str;//调用bool operator== (const char*   lhs, const string& rhs);
}

getline

在这里插入图片描述
当我们使用cin读取一个字符串的时候,当遇到" "或"\n"的时候会结束,但是当我们需要读取AA bbb cc这样一字符串,很显然cin已无法满足,需要借助getline,它只会读取到\n才会结束

如求最好一个单词的长度

#include <iostream>
using namespace std;
#include <string>
int main() {
    
    
    string str;
    getline(cin,str);
    size_t pos = str.rfind(' ');
    cout<<str.size()-pos-1<<endl;
}

三、总结

关于string的使用就先讲到这里吧,对于string,只使用的话借助使用文档就可以很轻松的使用。想要了解更多C++方面的知识,关注我!!!

猜你喜欢

转载自blog.csdn.net/m0_54469145/article/details/130730972
今日推荐