栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

【C++】string

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【C++】string

考试周...真是要命

-------------

什么是string,为什么要学习string
C 语言中,字符串是以 '' 结尾的一些字符的集合,为了操作方便, C 标准库中提供了一些 str 系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP 的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。

在刷题的时候也经常可以看到一些题目:

类似将字符串交换位置、相加、转化整形等

在这些题目里面,题目基本都是以string类的形式出现:

string是字符串类型,对于字符串的操作用string来会更加简单、方便且快捷

---------

标准库的string

这里有一个C++的网站可以帮助我们来了解string,缺点是全英文

string - C++ Reference (cplusplus.com)

这里借用参考的翻译:

1. 字符串是表示字符序列的类 2. 标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作单字节字符字符串的设计特性。 3. string 类是使用 char( 即作为它的字符类型,使用它的默认 char_traits 和分配器类型 ( 关于模板的更多信息,请参阅basic_string) 。 4. string 类是 basic_string 模板类的一个实例,它使用 char 来实例化 basic_string 模板类,并用 char_traits和allocator 作为 basic_string 的默认参数 ( 根于更多的模板信息请参考 basic_string) 。 5. 注意,这个类独立于所使用的编码来处理字节 : 如果用来处理多字节或变长字符 ( 如 UTF-8) 的序列,这个类的所有成员( 如长度或大小 ) 以及它的迭代器,将仍然按照字节 ( 而不是实际编码的字符 ) 来操作。

大概也就是看着多,这里可以这么理解:

string是一个字符串类型

这个类里面的操作办法跟常规的接口相同,然后加了一些专门操作string的函数

 string的底层是basic_string模板类的别名

不能操作多字节或者变成字符的序列

要包含头文件

常用的几个接口 

初始构造:

string有以下几个构造的办法:

    string c1 = "hellow world"; //通过字符串的初始赋值
	string c2("hello world");   //同上
	string c3(c1);//拷贝构造

除此之外,还有多种构造:

    string c4("hello worldxxxxxxxx", 11); //截取长字符串的前n个字符
    string c5(10, 'c');	//开十个字节的空间并全部初始化为字符c
	string c6("xxxhello worldxxxx", 3, 11); //用一个常量字符串的下标为3的位置到下表为11的位置初始化c6

总之,挺多的,当然,也可以什么都不给,创见一个空的字符串:

string c7;

但是如果直接去打印出来看的话,会发现这里直接空的一排:

如果这个时候调试,我们会看到这样的三个数值 

size、capacity和原始试图,暂且不管最后的原始视图,先看前面两个参数:

size指的是string里面有的字符数量,而capacity则是还可以放多少

这里什么都没打印出来,里面真一个字符都没有吗?

倒也不是

因为它(C++)要兼容C,所以这里其实还有一个''

-------

string的容量操作

这里要介绍几个常用的:

size:返回字符串的有效字符长度

length:返回字符串有效字符长度(跟上面类似,甚至功能重叠,还是C的问题...)

capacity:返回空间总大小

empty:检查字符串是否为空,如果为空就返回true,反之

clear:清空有效字符串

reserve:为字符串保留空间

resize:将有效字符串的个数改成n个,其他的空间会被字符填充

----

一个一个来看:

size和length

 

 可以看到返回的字符大小里面不包括最后的’‘

----------

capacity

上面我们拿一个空字符串来看的时候这里的capacity也是15,所以string的初始字符串容量是15个字节,这里提一下,如果空间不够用的话它会自动扩容,大小大概是自身的1.5倍

-------------

empty

 

-----------

clear

 

可以看到第一次还能打印出hello world,在用过一次clear后就什么也打印不出来了

------------

reverse 

这里,c1原本是容量是15,初始化hello world用了11的空间,剩4个,然后我reserve里面填20,让编译器给我保留20个字节的空间,它就扩容11+20 = 31个字节的空间

这是往大了扩,加入我要往小了,会发生什么?

 

可以看倒初始的容量是15个字节,15-11=4,这里还剩4个字节的空间,我要保留2个字节:

 

还是15个字节,也就是说它不会往小了改变容量,如果这里看的不详细,我们把容量变大一点:

首先15个字节的空间,开辟到200,然后再缩减到50,可以看到里面的容量还是200,没有改变。

再看详细一点,打开调试:

一开始的11个字节和15容量没有截图,这里是扩容至200:

 这里已经运行到减容至50,但实际容量还是没有改变,size也没有改变:

--------

resize

同样的例子,如果用resize,会有什么变化吗?

 表面上看是没有的,但如果我们打开调试:

 

如果一开始创建,里面有11个字节,容量是15,剩4个,如果往下将大小调整至200:

c1的size(有效个数)来到了200,但是容量还是没有变,我们再将resize调整至50:

可以看到里面的size已经变成了50,但是capacity还是没有改变,也就是说:

resize和reserve都不会改变已经开好的容量,但不同的是,resize在减容的时候会将size修改至要更改的大小并用’‘填充

----------

这里简单总结一下

注意: 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 不会改变容量大小。

---------

string类对象的访问及遍历操作 

先看看访问其普通成员,在C里面可以通过下标来访问,这里就直接看看代码:

 普通的没有问题,如果是const:

它就会报错

至于为什么这里可以用方括号访问下标,其实是类里面的一个重载:

string::operator[] - C++ Reference (cplusplus.com) 

这里有兴趣可以看这个网站

---------

我们知道,在C语言里面有这么几种遍历字符串的操作:

for循环,下标

while指针读取

在C++里面,这是否也可以用?

直接试试:

for循环

    string c1 = "hello world"; 
	for (int i = 0; i < c1.size(); i++)
	{
		cout << c1[i];
	}

----

迭代器

这个迭代器可以说是通用的,它是检查容器元素并遍历的一种数据类型,之后的数组等也可以用这个,这个分为以下几种:

1) 正向迭代器,定义方法如下:

容器类名::iterator  迭代器名;

2) 常量正向迭代器,定义方法如下:

容器类名::const_iterator  迭代器名;

3) 反向迭代器,定义方法如下:

容器类名::reverse_iterator  迭代器名;

4) 常量反向迭代器,定义方法如下:

容器类名::const_reverse_iterator  迭代器名;

知道了string的迭代器,那之后再对数组遍历也差不多:

这里做一个示范:

    string c1 = "hello world"; 
	string::iterator it = c1.begin();
	while (it != c1.end())
	{
		cout << *it;
		++it;
	}

 首先格式是

string::iterator X = 数组名.begin();

这里就可以得到数组的首元素地址,同理,如果将最后的begain变成end,那就可以获得数组最后一个元素的位置,就可以开始遍历;

这个还有另一个版本

rbegin和rend

跟上面操作是一样的,就不多说了

--------

范围for

for (char c : c1)
	{
		cout << c;
	}

怎么说呢,这个看上去很好用,实际上还是调用的迭代器,就,看看就好

------------

未完待续

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/951631.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号