C++第十四节课 string接口函数

字符串的扩容

扩容是要付出代价的,如果是原地扩容的效率还可以,但如果是异地扩容的话效率会比较低!

  • reverse  ---  反转;
  • reserve  --- 保留;

reserve

  • 调整字符串的容量,将其调整为n;
  • 如果 n 大于当前字符串容量,则该函数会导致容器将其容量增加到 n 个字符(或更大)。

例如,我知道了当前需要的空间为100,那么我可以通过reserve设置容量,从而避免了持续扩容降低效率;但是设置开辟空间大小为100,真正开辟的空间不一定为100!(与vs对齐等一些机制有关);

void TestPushBackReserve()
{
	string s;
	s.reserve(100);
	size_t sz = s.capacity();
	cout << sz << endl;
}

int main()
{
	TestPushBackReserve();
	return 0;
}

对于上面的代码,默认reserve想要开辟的空间为100,但是实际开辟的大小为111!

 但是在g++的编译下,默认reserve申请的空间大小等于capacity!

当我们使用resreve进行缩容的时候:容器可以自由优化,使得capacity  > n 即可!

void TestPushBackReserve()
{
	string s;
	s.reserve(100);
	size_t sz = s.capacity();
	cout << sz << endl;

	// 尝试缩容
	s.reserve(10);
	sz = s.capacity();
	cout << sz << endl;
}

int main()
{
	TestPushBackReserve();
	return 0;
}

我们发现:当我们想要其缩容到10的时候,但是capacity的大小为15!(在其他情况下编译器也可能出现不缩容的情况!)

底层的判断可能跟有效数据的个数有关,当调用clear清除有效数据的时候,大概率会执行缩容!

resize

作用:将字符串大小调整为n个字符的长度!

  • 如果 n 小于当前字符串长度,则当前值将缩短为其前 n 个字符,并删除第 n个字符以外的字符。
  • 如果 n 大于当前字符串长度,则通过在末尾插入所需数量的字符来扩展当前内容,以达到 n 的大小。如果指定了 c,则新元素将初始化为 c 的副本,否则,它们是值初始化字符(空字符)。(默认填充的是/0

reverse是单纯的扩容/缩容,只对capacity进行改变;

但是resize会改变size和capacity!同时对值进行初始化 / 删除有效字符个数!

缩容实际上也是讲原来的空间释放掉!再找一份新的合适的空间!(因此考虑效率问题,编译器一般都不会轻易进行缩容! --- 系统不支持分段释放!)

注意点:

对于operator来说,第二个重载函数的const修饰的是*this,也就是说调用[]的对象的值不能改变!

at

作用:获取一个字符在字符串中的位置,同时,at也支持字符串的修改!与[]的作用一致!

但是两者的差别在于:当访问有效范围之外的时候:

  • at会直接报异常;
  • []是会进行断言;
int main()
{
	//TestPushBackReserve();
	string s1("hello world");
	s1.at(1) = 'x';
	cout << s1 << endl;
	//s1.at(15);
	s1[15];
	return 0;
}

当使用at访问越界元素的时候: 报错!

当使用[]访问越界元素的时候:断言! 

assign

将一个string重新赋值,替换原来的内容!

insert

作用:讲其他字符插入到pos位置上的字符的前面;

下面是insert的一些操作:

	string s1("hello world");
	s1.append("111");
	cout << s1 << endl;
	s1.insert(0, "xxxxx");
	cout << s1 << endl;
	s1.insert(5, "world");
	cout << s1 << endl;
	s1.insert(s1.begin(), 'q');
	cout << s1 << endl;
	s1.insert(s1.begin() + 10, 10, 'y');
	cout << s1 << endl;

insert有效率的问题,因此用的时候需要谨慎对待!

erase 

  • 从pos位置删除len个字符(包含pos位置上的字符),如果len位置上不写,则默认删除pos之后的所有字符;
  • 删除迭代器p位置上的字符;

示例代码:

int main()
{
	string s1("hello world");
	s1.erase(0, 1);  // 头删
	cout << s1 << endl;
	s1.erase(s1.begin());  // 也是头删
	cout << s1 << endl;
	return 0;
}

谨慎使用!效率也不是很高!

replace 

作用:从pos位置开始,len个位置之后的字符串内容替换为新的内容

应用:

假如说有一个题目: 将一个字符串所有的空格替换为20%

解法如下:

int main()
{
	string s2("hello world");
	string s3;
	for (auto ch : s2)
	{
		if (ch != ' ')
		{
			s3 += ch;
		}
		else
		{
			s3 += "20%";
		}
	}
	return 0;
}

c_str

作用:获取等效的C语言的字符串(返回一个指向数组的指针,该数组包含了以null结尾的字符序列,表示字符串对象的当前值)

int main()
{
	string s2("hello world");
	string s3;
	for (auto ch : s2)
	{
		if (ch != ' ')
		{
			s3 += ch;
		}
		else
		{
			s3 += "20%";
		}
	}
	cout << s3 << endl;
	cout << typeid(s3).name() << endl;

	cout << s3.c_str() << endl;
	cout << typeid(s3.c_str()).name() << endl;

	return 0;
}

这里的s3是一个类,但是s3.c_str()是一个C语言类型的字符串!

因为两个类型调用cout的实际意义不一样!

  • s3调用cout实际上是运算符的重载(流插入),可以使用自定义类型;
  •  s3.c_str()是一个自定义类型!

c_str()是为了让字符串更好的与一些接口函数进行配合!

有些接口函数的参数必须是C语言类型的(指针!),不能是string类型的,因此此时需要c_str()这个函数!

find

作用:在字符串中查找指定的参数(参数为字符串 / 字符),并返回其下标 --- 返回第一个字符匹配的位置(没有找到返回42亿); 

指定pos时,则默认从pos位置之后开始搜索(包含pos位置),没有指定pos则从头开始搜索!

substr

作用:返回一个从对象中提取的子字符串;

子字符串是从pos位置开始,提取长度为len的子字符串,且len位置为空,默认提取到结尾!

小测试:通过使用string中类的接口函数将一个网址分割:

int main()
{
	string ur1("https://cplusplus.com/reference/string/string/?kw=string");
	// 网站分为: 协议  域名  资源名
	size_t pos = ur1.find("://");
	string protocal;  // 定义协议
	if (pos != string::npos)
	{
		protocal = ur1.substr(0, pos);
	}
	cout << protocal << endl;
	size_t pos2 = ur1.find( '/', pos + 3);
	string domain;  // 定义域名
	string uri;   // 定义资源名

	if (pos2 != string::npos)
	{
		domain = ur1.substr(pos + 3, pos2 - pos - 3);
		uri = ur1.substr(pos2 + 1);
	}
	cout << domain << endl;
	cout << uri << endl;
	return 0;
}

rfind

功能:其功能与find类似,但是区别是rfind是从后往前找的!

指定pos位置的时候,搜索只从pos位置之前开始找,pos位置之后不搜索!

find_first_of

作用:在字符串中搜索所有与参数匹配的所有字符!

// string::find_first_of
#include <iostream>       // std::cout
#include <string>         // std::string
#include <cstddef>        // std::size_t

int main ()
{
  std::string str ("Please, replace the vowels in this sentence by asterisks.");
  std::size_t found = str.find_first_of("aeiou");
  while (found!=std::string::npos)
  {
    str[found]='*';
    found=str.find_first_of("aeiou",found+1);
  }

  std::cout << str << '\n';

  return 0;
}

会将字符串中所有出现的"aeiou"替换为'*';

getline 

作用:从is中提取字符串到str中,直到找到分隔符(默认不控制就是遇到换行符结束);

采用第一种形式可以控制结束符!

cout/cin默认:多个值默认通过空格或换行来间隔,遇到空格或者换行,就认为当前独立的值已经结束!

因此,如果要读取一个字符串,这个字符串中含有空格,那么使用cin/cout是读取不到的!

此时剩下的T还在缓冲区当中!

计算机显示的是字符,但是底层在计算机中存储的是ASCII的值;

ASCII码表无法显示汉语!

  • gbk(中文编写)
  • unicode(万维码)

一般情况下,两个字符编写一个汉字;

不同的string类型是为了更好的适应各个国家语言的文字!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一道秘制的小菜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值