自学内容网 自学内容网

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类型是为了更好的适应各个国家语言的文字!


原文地址:https://blog.csdn.net/weixin_47702917/article/details/142407044

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!