string类基本使用

发布于:2023-01-22 ⋅ 阅读:(15) ⋅ 点赞:(0) ⋅ 评论:(0)

1️⃣关于string类(标准库)

1、string是表示字符串的字符串类。
2、string类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
3、string类是使用char,string在底层是:basic_string模板类的别名,typedef basic_string<char,char_traits,alloctaor> string。
4、string类是basic_string模板类的一个实例,它使用char来实例化basic_string模板类,并用char_traits和allocator作为basic_string的默认参数。
5、string类独立于所使用的编码来处理字节:若用来处理多字节或者变长字符(UTF-8等)的序列,string类的所有成员以及它的迭代器,将仍热按照字节来操作,而不是按照实际编码的字 符来操作。

2️⃣string类常用接口

string类常见构造

在这里插入图片描述

(constructor)函数名称 功能
string() 构造空的string类对象,即构造空字符串
string(const char * s) c_string构造string类对象
string(const string& str) 拷贝构造函数
string(size_t n,char c) 用n个字符c来构造string类对象
int main()
{
	string s1;  //构造空的string类对象s1

	string s2("world");   //用c形式的字符串构造string类对象s2
	string s3 = "world";

	string s4(s3);  //用s3拷贝构造s4

	string s5(5, 'x'); //用5个字符x来构造s5
	return 0;
}

string类对象的容量操作

resize

⚽️将有效字符的个数该成n个,多出的空间用字符c填充
在这里插入图片描述

int main()
{
	string s1("resize");
	s1.resize(15);
	string s2("resize");
	s2.resize(15, 'x');
	return 0;
}

reserve

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

🚀用reserve来提高插入数据的效率,避免频繁的增容带来的开销

void TestReserve()
{
	string s;
	s.reserve(115);
	size_t sz = s.capacity();
	
	cout << "make s grow" << endl;
	for (int i = 0;i < 115;++i)
	{
		s.push_back('x');
		if (sz != s.capacity())
		{
			sz = s.capacity();
			cout << "capacity changed : " << sz << endl;
		}
	}
}

运行测试:
在这里插入图片描述

void Teststring2()
{
	string s;
	// 测试reserve是否会改变string中有效元素个数
	s.reserve(100);
	cout << s.size() << endl;
	cout << s.capacity() << endl;
	// 测试reserve参数小于string的底层空间大小时,是否会将空间缩小
	s.reserve(50);
	cout << s.size() << endl;
	cout << s.capacity() << endl;
}

size/length/capacity

⚽️size - 返回字符串中有效字符的长度
⚽️length - 返回字符串中有效字符的长度
⚽️capacity - 返回当前为该字符串分配的存储空间的大小

int main()
{
	string s("teststring");
	cout << s.size() << endl;          //有效字符长度
	cout << s.length() << endl;        //有效字符长度
	cout << s.capacity() << endl;      //所开空间大小
	return 0;
}

empty

⚽️ 检测字符串是否为空串,是则返回true,否则返回false
在这里插入图片描述

clear(重点)

⚽️ 清空字符串的内容,它变成一个空字符串(长度为0个字符)。在这里插入图片描述

在这里插入图片描述

总结一下:

  1. size()与length()方法底层实现原理完全相同,实现size()的目的是与其它容器的接口保持一致,平时用size()会比较多。
  2. clear()只是将字符串中的有效字符清空,并不改变底层空间的大小。
  3. resize在改变元素的个数时,若将元素的个数增多,可能会改变底层容量的大小,若元素个数减少,底层空间大小不改变(一般不会缩空间)。
  4. reserve为string预留空间,不改变有效元素个数,若reserve的参数小于string的底层空间大小时,reserve不会改变容量大小。

3️⃣string类对象的修改

operator +=

⚽️通过在当前值的末尾添加额外的字符来扩展字符串:
在这里插入图片描述

int main()
{
	string s1 = "!!!!";
	string s("pushback");
	s += " ";
	s += "追加";
	s += s1;
	cout << s << endl;
	return 0;
}

运行测试:
在这里插入图片描述

appened

⚽️通过在当前值的末尾添加额外的字符来扩展字符串。在这里插入图片描述

int main()
{
	string s1("hello");
	cout << s1 << endl;
	s1.append("world");
	cout << s1 << endl;

	string s2("!!!!!!");
	s1.append(s2.begin(), s2.end());
	cout << s1 << endl;
	return 0;
}

运行测试:
在这里插入图片描述

push_back

⚽️将字符c追加到字符串的末尾,使其长度增加1。
在这里插入图片描述

void TestPushBack()
{
	string s("hell");
	s.push_back('o');
	cout << s << endl;
}

c_str

⚽️ 返回一个指向数组的指针,该数组包含一个以空结束的字符序列(即C-string),表示string对象的当前值。
在这里插入图片描述

void TestC_str()
{
	string s("frangrance  jeak");
	cout << s << endl;             //调用 operator<<(cout,s1)
	cout << s.c_str() << endl;     //调用 operator<<(cout,const char*)
}

find

⚽️从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置。
在这里插入图片描述
⁉️:如和写一个程序取出网址中的协议名和域名。
在这里插入图片描述

//取出url中的域名
string GetDomain(const string& url)
{
	size_t pos = url.find("://");  
	if (pos != string::npos) 
	{
		size_t start = pos + 3;
		size_t end = url.find('/', start);
		if (end != string::npos)
			return url.substr(start, end - start);
		else
			return string();
	}
	else
		return string();
}

//取出url中的协议
string GetProtocol(const string& url)
{
	size_t pos = url.find('://');
	if (pos != string::npos)
		return url.substr(0, pos - 0);
	else
		return string();
}

int main()
{
	string url1 = "https://cplusplus.com/reference/string/string/?kw=string";
	string url2 = "https://blog.csdn.net/";
	cout << GetDomain(url1) << endl;
	cout << GetDomain(url2) << endl;

	cout << GetProtocol(url1) << endl;
	cout << GetProtocol(url2) << endl;
	return 0;
}

rfind

⚽️ 从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置。
在这里插入图片描述
⁉️:取出文件名的后缀

//要求取出文件名的后缀
int main()
{
	string filename = "test.txt.zip";
	size_t pos = filename.rfind('.');
	if (pos != string::npos)
	{
		string suff = filename.substr(pos);
		cout << suff << endl;
	}
	return 0;
}

总结一下:
1、在string尾部追加字符时,push_back / append / += 三种的实现方式基本没有什么区别,一般情况下使用string类的+=比较多,+=既可以连接单个字符,也可以连接字符串。
2、操作string时,若能够预测到大约需要多少空间可以通过reserve提前开好空间,避免频繁扩容而带来的损耗。

4️⃣非string类成员函数

|

5️⃣string类对象的遍历

函数名称 功能
operator[] 返回特定位置的字符,const string类对象调用
begin+end begin获取一个字符串的迭代器 + end获取字符串最后一个位置的下一个位置的迭代器
rbegin+rend begin获取一个字符串的迭代器 + end获取字符串最后一个位置的下一个位置的迭代器

🔵遍历方式1:for + operator[]

int main()
{
	string s("ejfkaj  afkjkajf");
	for (size_t i = 0;i < s.size();++i)
	{
		cout << s[i] << " ";
	}
	cout << endl;
	return 0;
}

🔵遍历方式2:迭代器
🚀[begin(),end()) end()返回的不是最后一个数据位置的迭代器,返回是最后一个位置的下一个位置。
需要注意的是,c++中迭代器一般都是给的[)左闭右开区间。

// 正向迭代器
int main()
{
	string s("fhajh ahfjh");
	string::iterator it = s.begin();
	while (it != s.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
	return 0;
}
//反向迭代器
int main()
{
	string s("123fhajh");
	string::reverse_iterator rit = s.rbegin();
	while (rit != s.rend())
	{
		cout << *rit << " ";
		++rit;
	}
	cout << endl;
	return 0;
}

❗️string,vector等支持[]遍历,但是list,map等容器不支持[]

🔵遍历方式3:范围for
🚀 c++11提供范围for,写起来更方便。一次取容器中的数据赋值给e,自动判断结束。

int main()
{
	string s("ejfkaj  afjak");
	for (auto& e : s)
	{
		cout << e << " ";
	}
	cout << endl;

	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}