string stl用法,c++ string stl
Yyds干货库存
在写之前,我们终于接触到了C的STL,这是C模块非常重要的一部分可以说,如果你学过C而没有STL,你的C很可能是不完整的我们学习STL主要分两个层次,第一个可以用,第二个是了解他们的底层至于更高的层次,我还没达到,就不跟大家分享了先简单了解一下STL,有个大概的了解今天的主要内容是弦乐
STL STL(标准模板库)是什么:它是C标准库的重要组成部分,不仅是一个可复用的构件库,也是一个包含数据结构和算法的软件框架之前和大家分享过数据结构的知识,也和大家一起用C语言写过,但是可用性有点低当你写OJ题,用C语言的时候,你会发现有时候你要自己实现数据结构大佬们也有同样的烦恼,于是出现了STL,使用了泛型编程,这也是我们之前说模板的原因
STL版本我们学习STL有三个版本,都有大致相同的功能
原始版本亚历山大·斯捷潘诺夫、孟利在惠普实验室完成了原始版本这是STLP的原作j版本继承了HP版本,被micro VS系列使用代码可读性SGI版本继承自HP版本GCC(Linux)采用,移植性好,可读性高后面学STL的时候要看一些源代码,主要参考的就是这个版本STL组件STL的六个组件,直接看图吧,后面的内容会涉及到在这里,我们先了解一下
我们先来了解一下什么是弦简单来说,string就是我们在C语言中所知道的字符串在OJ中,关于string的话题基本都是以string类的形式出现的在日常工作中,为了简单、方便、快速,基本都是使用string类,很少有人使用C库中的字符串操作函数因为我们比较常用,大佬们就把这个变成了模板类从某种意义上说,string不属于STL,它的出现要早得多
我们来看看STL中字符串的分类我们可能会疑惑为什么这里有四种弦?我们想学哪个?SLT不就是个模板吗?为什么这里的字符串看起来不一样?让我们逐一解决这些问题
字符表之前先讲为什么有四种字符串?我们需要谈谈什么是字符码表我们都知道,在计算机世界里,他们只知道0和1,但在现实世界里,我们有汉语和英语这样的语言怎样才能把现实世界和电脑世界联系起来?这就是字符编码表的作用原来的字符编码表是美国提出的,叫ASCII码,不支持中文
为了对属于各自国家的字符列表进行编码,中国编制了GBK,它使用16位二进制系统但是,各国并没有统一的标准此时,国际组织ISO制定了Unicode,也称为通用代码
我们已经知道了角色列表的历史所谓四种字符串,就是支持不同位的字符是的,我们不仅仅使用char作为字符类型我们主要学的是弦乐它们的四种用法都差不多如果你学会了一个,你可以为其他人检查文件
int main()
{
cout string: sizeof(char)endl;
cout u16 string: sizeof(char 16 _ t)endl;
cout u32 string: sizeof(char 32 _ t)endl;
cout wstring: sizeof(wchar _ t)endl;
返回0;
}
这是一个字符串模板代码是的,我们看到的字符串是typedef,也就是说,它是一个带有char类型参数的模板
在字符串的底部,字符串的底部是一个可以动态开发的字符数组我们必须记住这一点稍后,当我们模拟实现时,我们将遵循这一点
int main()
{
字符串s( hello );
返回0;
}
让我们仔细看看这个数组,以避免出现问题
现在我们可以使用字符串当我们使用它时,我们需要头文件,我们还需要释放std中的字符串少说多做让我们看看
#包括iostream
#包含字符串
使用STD:string;
int main()
{
STD:string S1;//或者直接释放
字符串S2;
返回0;
}构造函数现在我们可以正式接触string的内容了注意,C98的string中有七个构造函数,但并不是所有的都是常用的在这里,我介绍其中的四个
构造器
功能描述
字符串()
构造一个空字符串
字符串(常量字符串str)
复制构造,深层复制
字符串(const char* s)
由字符串构成
字符串(size_t n,char c)
用n C个字符构造一个字符串
现在我们单独演示一下
string()int main()
{
字符串s;
返回0;
}
string(const char* s)int main()
{
字符串s( hello string );
返回0;
}
string(size_t n,char c)int main()
{
字符串s(10, a );
返回0;
}
string(const string str)int main()
{
字符串S1(“hello”);
字符串S2(S1);
返回0;
}
Length我们知道string的底层是一个动态打开的数组,所以string支持计算我们string对象的有效长度和容量的函数我们直接去看看吧
size() length()都用来计算字符串对象的有效长度唯一的区别是函数名不同Length()是原始方法我们字符串的有效长度可以用length来描述,但是下面的哈希表有点不合理,所以增加了size()函数为了保持命名的规范性,仅此而已
int main()
{
字符串s( hello );
cout s . size()endl;
cout s . length()endl;
返回0;
}
Capacity()是当前对象的容量,即数组的长度
int main()
{
字符串s( hello );
cout s . capacity()endl;
返回0;
}
max_size()函数是我们的字符串的最大长度一般没人用我就在这里提一下
int main()
{
字符串s;
cout s . max _ size()endl;
返回0;
}
()字符串处的运算符[\]重载运算符[\],该运算符可以支持下标访问这里at()的功能和[\]是一样的,不过是早期版本,功能上没有区别
int main()
{
字符串s( hello );
cout s[1]endl;
cout s . at(1)endl;
返回0;
}
越界访问如果我们访问一个有效字符的下一个位置,它将返回一个\0我们还不知道最底层,但我们知道空字符串包含一个\0,这是为了兼容C语言
int main()
{
字符串s( hello );
if (s[5]==\0 )
{
cout s[5]==\ \ 0 endl;
}
返回0;
}
但是如果我们越界了,VS编译器就会报错
int main()
{
字符串s( hello );
s[16];
返回0;
}
遍历字符串遍历字符串我们有三种方法,而这三种方法是我们经常使用的
使用下标,使用迭代器我们将关注###下标访问的使用范围
这个string类重载了运算符[\],string的底层是一个数组,支持随机访问
int main()
{
字符串s( hello );
for(size _ t I=0;I s . size();我)
{
cout s[I]“”;
}
cout endl
返回0;
}
迭代器访问也许你对迭代器还有点困惑,不知道它是什么好吧,我简单说一下,所谓的迭代器是我们遍历STL最常用的方法是的,你没看错,STL的底层并不是都是连续的空间,也就是说使用下标访问并不通用
string中的迭代器是原生指针,有四种迭代器让我们看一看
我可以通过两种方式直接访问这里的正向迭代器,一种是const-decorated,另一种是可修改的
这里是正向迭代器指向的地方注意end()指向的有效字符的下一个位置
你可以修改迭代器指向的内容
int main()
{
字符串s( hello );
string:iterator it=s . begin();
而(它!=s.end())
{
cout * it“”;
它;
}
cout endl
返回0;
}
如果要修改迭代器指向的内容,这里可以知道
int main()
{
字符串s( hello );
string:iterator it=s . begin();
而(它!=s.end())
{
(* it);
cout * it“”;
它;
}
cout endl
返回0;
}
如果不想修改迭代器指向的数据,可以直接调用const修饰的迭代器
这个迭代器主要应用于不想被修改的字符串让我们看看应用程序
void func(常量字符串str)
{
string:const _ iterator it=str . c begin();
而(它!=str.cend())
{
cout * it“”;
它;
}
cout endl
}
int main()
{
字符串s( hello );
func
返回0;
}
说完了正向迭代器,反向迭代器在这里说说它是什么它的功能是遍历字符串,但只是反向遍历
这个迭代器是可以修改的,所以这里不做修改
int main()
{
string str( hello );
string:reverse _ iterator rit=str . Rb egin();
while (rit!=str.rend())
{
cout * rit“”;
rit
}
cout endl
返回0;
}
现在有const修改的迭代器可以反转我们可以直接用它们,就不说细节了
int main()
{
string str( hello );
string:const _ reverse _ iterator rit=str . Cr begin();
while (rit!=str.crend())
{
cout * rit“”;
rit
}
cout endl
返回0;
}
range for的范围比较简单,但是有一个缺陷,就是必须遍历一次
int main()
{
string str( hello );
for(自动通道:str)
{
cout ch“”;
}
cout endl
返回0;
}
看起来很高大上,其实最底层也是迭代器的复用,这里复用的迭代器就是可以修改的迭代器
Push_back()字符串支持在末尾插入一个字符如果容量不足,编译器会自动扩展
int main()
{
字符串s;
s . push _ back( a );
s . push _ back( b );
s . push _ back( c );
s . push _ back( d );
cout s endl
返回0;
}
字符串扩展机制我们知道字符串的底层是一个动态数组现在我们想看看它是如何膨胀的
从这里可以看出,不同编译器的扩展规则是不一样的VS下,膨胀1.5倍,G是2倍而且一开始VS开辟了15个空格,G没有
Reserve()众所周知,扩展是有成本的,有时候需要重新开辟空间,复制数组如果知道总开放空间,提前开放不是更好吗?这就是这个函数的作用
只改变容量不改变大小,也就是你可以理解为只是在扩大
注意,reserve()函数创建的空间不一定和我们想要的一样它需要内存对齐,但它是完全不同的
int main()
{
字符串s;
美国储备银行(100);
返回0;
}
但这里有两个问题如果我们的n大于现有存在的容量会怎么样,小于它会怎么样?在这里讨论一下吧
n容量和上面一样,会自动扩充容量,只改变容量,不改变大小
int main()
{
字符串s( aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa );
int size=s . size();
cout size endl
s . reserve(s . capacity()20);
返回0;
}
如果发生这种情况,什么都不会改变
int main()
{
字符串s( aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa );
cout original size s . size()endl;
cout original capacity()s . capacity()endl;
美国储备银行(15);
cout size s . size()endl;
cout capacity()的s . capacity()endl;
返回0;
}
resize()的作用从名字就能看出来是重置大小,也就是说我们重新指定了数据最后插入的地方,如果空间不够,编译器会自动扩充容量但是这里有两个函数,本质上是一个默认函数
int main()
{
字符串s;
cout size s . size()endl;
cout capacity()的s . capacity()endl;
s . resize(20);
cout size s . size()endl;
cout capacity()的s . capacity()endl;
返回0;
}
Void resize (size_t n)这是重置n个空格从开始数到n的下标,这个和所有的重置空格都会变成\0这里有三种情况这里我们将讨论两种常见的情况,第三种是扩展情况
情况一
int main()
{
字符串s;
s . push _ back( a );
s . push _ back( b );
s . push _ back( b );
s . push _ back( b );
s . push _ back( b );
s . resize(2);
返回0;
}
情况2
int main()
{
字符串s;
s . push _ back( a );
s . push _ back( b );
s . push _ back( b );
s . resize(7);
返回0;
}
我在这里总结一下resize是指在有效元素的最后一个位置之后改变位置,改为下标N,将原来有效位置的距离改为\0
Void resize (size_t n,char c)甚至更简单没什么好说的也符合以上两条规律,也符合不足展开规律就是把默认的\0改成我们想要的字符,其他情况这里就不解释了
int main()
{
字符串s;
s . push _ back( a );
s . push _ back( b );
s.resize(20, 1 );
cout s endl
返回0;
}
Clear()清除有效字符,在VS下不会收缩,取决于编译器自己的选择
int main()
{
字符串s( hello );
美国储备银行(100);
s . clear();//只改变大小,缩小体积,但不要缩小体积看编译器
返回0;
}
Append()我们发现push_back尾部插入是可以的,但是支持插入一个字符我们想插入一个字符串,可以吗?String也提供了这个接口简单介绍一下最长的
追加()
功能描述
string append(const string str);
在末尾插入一个字符串对象
字符串追加(const char * s);
在末尾插入一个字符串
模板字符串append (InputIterator在前,InputIterator在后);
使用迭代器尾部插值
让我直接演示这些函数用法比较简单这里新的迭代器尾部插入是我们从未见过的还是单独用吧
int main()
{
字符串s( hello );
s . append( qkj );
cout s endl
S2(“你好”);
s .追加(SO2);
cout s endl
返回0;
}
字符串追加(首先输入迭代器,最后输入迭代器)非常容易就是末尾插了从第一个到最后一个的内容,没什么神奇的我们将在接下来的几篇博客中讨论迭代器
int main()
{
字符串s( hello );
S2(“你好”);
s.append(s2.begin()、S2 . end());
cout s endl
返回0;
}
Operator=与上面的append相比,这是我们经常使用的,也更容易理解
我们会经常用到这个
int main()
{
字符串s( hello );
s= aaaa
cout s endl
s= c
cout s endl
字符串s2(哈哈哈);
s=s2
cout s endl
返回0;
}
Insert()一般情况下,我们不使用这个函数,但是我们都使用尾部插入不过为了让你知道,我们这里就拿出来给大家简单介绍一下常用的
插入()
功能描述
string insert (size_t pos,const string str);
在pos位置插入一个字符串
字符串插入(size_t pos,const char * s);
迭代器插入(迭代器p,char c);
每个人都可以使用它
int main()
{
字符串S1(“hello”);
字符串S2( qkj );
s1 .插入(5,S2);
cout s1 endl
s1 .插入(2,’xxxxx
x’);
cout s1 endl
string:iterator it=S1 . begin();
s1.insert(it 2, 1 );
cout s1 endl
返回0;
}
擦除()
这个删除下标是从pos中len字符。如果不传人物,删除NPO。这里的npos是一个静态常数,数据量很大。
int main()
{
字符串S1(“hello”);
s1.erase(1,3);
cout s1 endl
返回0;
}
至于迭代器,我就不给你看了。
swap()字符串中有一个swap函数,当然我们std中的那个也可以用,但是需要深度复制,效率有点低。
int main()
{
字符串S1(“hello”);
字符串S2( qkj );
cout s1 endl
cout s2 endl
S1 . swap(S2);
cout s1 endl
cout s2 endl
返回0;
}
函数c_str()返回这个数组的指针。在工作中,有一些指针不接受字符串。这里需要字符串里面的指针,可能还没什么用。
int main()
{
字符串S1(“hello”);
const char * str=S1 . c _ str();
cout str endl
返回0;
}
Find()find()是找出字符串中是否有我们想要的字符或字符串。默认情况下,它从下标0开始,返回字符的下标或字符串的开头位置。如果找不到,就退回NPO。
int main()
{
字符串S1(“hello”);
size_t pos=s1.find(e ,3);//从下标3开始
如果(pos!=string:NPO)
{
cout S1[pos]endl;
}
其他
{
Cout“未找到”endl
}
返回0;
}
int main()
{
字符串S1(“hello”);
size_t pos=s1.find(lo ,2);//从下标3开始
如果(pos!=string:NPO)
{
Cout found endl
}
其他
{
Cout“未找到”endl
}
返回0;
}
还有一个rfind()函数,是从string对象后面找到的,这里就不跟大家分享了。
Substr(),可以说是字符串截断函数,从pos位置开始用len字符截断,这里也是默认函数。
int main()
{
字符串S1(“hello”);
string s2=s1.substr(1,2);
cout s2 endl
返回0;
}
Getline()我们都知道,运算符遇到空格就结束,这里的string也是一样。
int main()
{
字符串s;
cin的;
cout s endl
返回0;
}
这个函数不是string独有的,它在std。
int main()
{
字符串s;
std:getline(南CIN);
cout s endl
返回0;
}
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。