C++基础之string类型_c++ string_樊同学爱编程的博客-程序员秘密

技术标签: c++  c  string  C++基础  基础  类型  

C++基础之string类型


string 类型支持长度可变的字符串,C++ 标准库将负责管理与存储字符相关的内存,以及提供各种有用的操作。标准库 string 类型的目的就是满足对字符串的一般应用。
与其他的标准库类型一样,用户程序要使用 string 类型对象,必须包含相关头文件。如果提供了合适的 using 声明,那么编写出来的程序将会变得简短些:

#include <string>
using std::string;

string 对象的定义和初始化

string 标准库支持几个构造函数。构造函数是一个特殊成员函数,定义如何初始化该类型的对象。下面列出了几个 string 类型常用的构造函数。当没有明确指定对象初始化式时,系统将使用默认构造函数。

string s1; 默认构造函数 s1 为空串
string s2(s1); 将 s2 初始化为 s1 的一个副本
string s3(“value”); 将 s3 初始化为一个字符串字面值副本
string s4(n, ‘c’); 将 s4 初始化为字符 ‘c’ 的 n 个副本

PS:因为历史原因以及为了与 C 语言兼容,字符串字面值与标准库 string 类型不是同一种类型。这一点很容易引起混乱,编程时一定要注意区分字符串字面值和 string 数据类型的使用,这很重要。

string 对象的读写

int main()
{
string s;				//定义一个空字符串
cin >> s;				//从标准输入读取 string 并将读入的串存储在 s 中
cout << s << endl;	
return 0;
}

PS:
string 类型的输入操作符:
读取并忽略开头所有的空白字符(如空格,换行符,制表符)。
读取字符直至再次遇到空白字符,读取终止。
如果给定输入是"Hello World!"(注意到开头和结尾的空格),则屏幕上将输出"Hello",而不含任何空格。

读入未知数目的 string 对象

和内置类型的输入操作一样,string 的输入操作符也会返回所读的数据流。因此,可以把输入操作作为判断条件。下面的程序将从标准输入读取一组 string 对象,然后在标准输出上逐行输出:

int main()
{
string word;
while (cin >> word)
cout << word << endl;
return 0;
}

上例中,用输入操作符来读取 string 对象。该操作符返回所读的 istream 对象,并在读取结束后,作为 while 的判断条件。如果输入流是有效的,即还未到达文件尾且未遇到无效输入,则执行 while 循环体,并将读取到的字符串输出到标准输出。如果到达了文件尾,则跳出 while 循环。

使用 getline 读取整行文本

另外还有一个有用的 string IO 操作:getline。这个函数接受两个参数:一个输入流对象和一个 string 对象。getline 函数从输入流的下一行读取,并保存读取的内容到不包括换行符。和输入操作符不一样的是,getline 并不忽略行开头的换行符。只要 getline 遇到换行符,即便它是输入的第一个字符,getline 也将停止读入并返回。如果第一个字符就是换行符,则 string 参数将被置为空 string。
getline 函数将 istream 参数作为返回值,和输入操作符一样也把它用作判断条件。例如,重写前面那段程序,把每行输出一个单词改为每次输出一行文本:

int main()
{
string line;
while (getline(cin, line))
cout << line << endl;
return 0;
}

由于 line 不含换行符,若要逐行输出需要自行添加。照常,我们用 endl 来输出一个换行符并刷新输出缓冲区。
由于 getline 函数返回时丢弃换行符,换行符将不会存储在 string 对象中。

string 对象的操作

s.empty() 如果 s 为空串,则返回 true,否则返回 false。
s.size() 返回 s 中字符的个数
s[n] 返回 s 中位置为 n 的字符,位置从 0 开始计数
s1 + s2 把 s1 和s2 连接成一个新字符串,返回新生成的字符串
s1 = s2 把 s1 内容替换为 s2 的副本
v1 == v2 比较 v1 与 v2的内容,相等则返回 true,否则返回 false
!=, <, <=, >, and >= 保持这些操作符惯有的含义

string 的 size 和 empty 操作

string 对象的长度指的是 string 对象中字符的个数,可以通过 size 操作获取:

int main()
{
string st("The expense of spirit\n");
cout << "The size of " << st << "is " << st.size()
<< " characters, including the newline" << endl;
return 0;
}

编译并运行这个程序,得到的结果为:

The size of The expense of spirit
is 22 characters, including the newline

了解 string 对象是否空是有用的。一种方法是将 size 与 0 进行比较:

if (st.size() == 0)
// ok: empty

本例中,程序员并不需要知道 string 对象中有多少个字符,只想知道 size 是否为 0。用 string 的成员函数 empty() 可以更直接地回答这个问题:

if (st.empty())
// ok: empty

empty() 成员函数将返回 bool,如果 string 对象为空则返回 true 否则返回 false。

string::size_type 类型

从逻辑上来讲,size() 成员函数似乎应该返回整形数值,或无符号整数。但事实上,size 操作返回的是 string::size_type 类型的值。我们需要对这种类型做一些解释。
string 类类型和许多其他库类型都定义了一些配套类型(companion type)。通过这些配套类型,库类型的使用就能与机器无关(machine-independent)。size_type 就是这些配套类型中的一种。它定义为与 unsigned 型(unsigned int 或 unsigned long)具有相同的含义,而且可以保证足够大能够存储任意 string 对象的长度。为了使用由 string 类型定义的 size_type 类型是由 string 类定义。
任何存储 string 的 size 操作结果的变量必须为 string::size_type 类型。特别重要的是,还要把 size 的返回值赋给一个 int 变量。
虽然我们不知道 string::size_type 的确切类型,但可以知道它是 unsigned 型。对于任意一种给定的数据类型,它的 unsigned 型所能表示的最大正数值比对应的 signed 型要大倍。这个事实表明 size_type 存储的 string 长度是 int 所能存储的两倍。
使用 int 变量的另一个问题是,有些机器上 int 变量的表示范围太小,甚至无法存储实际并不长的 string 对象。如在有 16 位 int 型的机器上,int 类型变量最大只能表示 32767 个字符的 string 个字符的 string 对象。而能容纳一个文件内容的 string 对象轻易就会超过这个数字。因此,为了避免溢出,保存一个 stirng 对象 size 的最安全的方法就是使用标准库类型 string::size_type。

string 关系操作符

string 类定义了几种关系操作符用来比较两个 string 值的大小。这些操作符实际上是比较每个 string。
PS: string 对象比较操作是区分大小写的,即同一个字符的大小写形式被认为是两个不同的字符。在多数计算机上,大写的字母位于小写之前:任何一个大写之母都小于任意的小写字母。
== 操作符比较两个 string 对象,如果它们相等,则返回 true。两个 string 对象相等是指它们的长度相同,且含有相同的字符。标准库还定义了 != 操作符来测试两个 string 对象是否不等。
关系操作符 <,<=,>,>= 分别用于测试一个 string 对象是否小于、小于或等于、大于、大于或等于另一个 string 对象:

string big = "big", small = "small";
string s1 = big;    // s1 is a copy of big
if (big == small)   // false
	 // ...
if (big <= s1)      // true
	// ...

关系操作符比较两个 string 对象时采用了和(大小写敏感的)字典排序相同的策略:

  • 如果两个 string 对象长度不同,且短的 string 对象与长的 string 对象的前面部分相匹配,则短的 string 对象小于长的 string 对象。
  • 如果 string 对象的字符不同,则比较第一个不匹配的字符。
    举例来说,给定 string 对象:
string substr = "Hello";
string phrase = "Hello World";
string slang  = "Hiya";

则 substr 小于 phrase,而 slang 则大于 substr 或 phrase

string 对象的赋值

总体上说,标准库类型尽量设计得和基本数据类型一样方便易用。因此,大多数库类型支持赋值操作。对 string 对象来说,可以把一个 string 对象赋值给另一个 string 对象;
大多数 string 库类型的赋值等操作的实现都会遇到一些效率上的问题,但值得注意的是,从概念上讲,赋值操作确实需要做一些工作。它必须先把 st1 占用的相关内存释放掉,然后再分配给 st2 足够存放 st2 副本的内存空间,最后把 st2 中的所有字符复制到新分配的内存空间。

两个 string 对象相加

string 对象的加法被定义为连接(concatenation)。也就是说,两个(或多个)string 对象可以通过使用加操作符 + 或者复合赋值操作符 +=(1.4.1 节)连接起来。给定两个 string 对象:

string s1("hello, ");
string s2("world\n");

下面把两个 string 对象连接起来产生第三个 string 对象:

string s3 = s1 + s2;   // s3 is hello, world\n

如果要把 s2 直接追加到 s1 的末尾,可以使用 += 操作符:

s1 += s2;   // equivalent to s1 = s1 + s2

和字符串字面值的连接

上面的字符串对象 s1 和 s2 直接包含了标点符号。也可以通过将 string 对象和字符串字面值混合连接得到同样的结果:

string s1("hello");
string s2("world");
string s3 = s1 + ", " + s2 + "\n";

当进行 string 对象和字符串字面值混合连接操作时,+ 操作符的左右操作数必须至少有一个是 string 类型的:

string s1 = "hello";  
string s2 = "world";
string s3 = s1 + ", ";           	//正确
string s4 = "hello" + ", ";      	//错误
string s5 = s1 + ", " + "world"; 	// 正确
string s6 = "hello" + ", " + s2;		// 错误

s3 和 s4 的初始化只用了一个单独的操作。在这些例子中,很容易判断 s3 的初始化是合法的:把一个 string 对象和一个字符串字面值连接起来。而 s4 的初始化试图将两个字符串字面值相加,因此是非法的。
s5 的初始化方法显得有点不可思议,但这种用法和标准输入输出的串联效果是一样的。本例中,string 标准库定义加操作返回一个 string 对象。这样,在对 s5 进行初始化时,子表达式 s1 + ", " 将返回一个新 string 对象,后者再和字面值 "world\n"连接。整个初始化过程可以改写为:

string tmp = s1 + ", "; 
s5 = tmp + "world";   

而 s6 的初始化是非法的。依次来看每个子表达式,则第一个子表达式试图把两个字符串字面值连接起来。这是不允许的,因此这个语句是错误的。

从 string 对象获取字符

string 类型通过下标操作符([ ])来访问 string 对象中的单个字符。下标操作符需要取一个 size_type 类型的值,来标明要访问字符的位置。这个下标中的值通常被称为“下标”或“索引”。
PS:
string 对象的下标从 0 开始。如果 s 是一个 string 对象且 s 不空,则 s[0] 就是字符串的第一个字符, s[1] 就表示第二个字符(如果有的话),而 s[s.size() - 1] 则表示 s 的最后一个字符。
引用下标时如果超出下标作用范围就会引起溢出错误。
可用下标操作符分别取出 string 对象的每个字符,分行输出:

string str("some string");
for (string::size_type ix = 0; ix != str.size(); ++ix)
	cout << str[ix] << endl;

每次通过循环,就从 str 对象中读取下一个字符,输出该字符并换行。

下标操作可用作左值

前面说过,变量是左值,且赋值操作的左操作的必须是左值。和变量一样,string 对象的下标操作返回值也是左值。因此,下标操作可以放于赋值操作符的左边或右边。通过下面循环把 str 对象的每一个字符置为 *:

for (string::size_type ix = 0; ix != str.size(); ++ix)
	str[ix] = '*';

计算下标值

任何可产生整型值的表达式可用作下标操作符的索引。例如,假设 someval 和 someotherval 是两个整形对象,可以这样写:
虽然任何整型数值都可作为索引,但索引的实际数据类型却是类型 unsigned 类型 string::size_type。
前面讲过,应该用 string::size_type 类型的变量接受 size 函数的返回值。在定义用作索引的变量时,出于同样的道理,string 对象的索引变量最好也用 string::size_type 类型。
在使用下标索引 string 对象时,必须保证索引值“在上下界范围内”。“在上下界范围内”就是指索引值是一个赋值为 size_type 类型的值,其取值范围在 0 到 string 对象长度减 1 之间。使用 string::size_type 类型或其他 unsigned 类型,就只需要检测它是否小于 string 对象的长度。
PS: 标准库不要求检查索引值,所用索引的下标越界是没有定义的,这样往往会导致严重的运行时错误。

string 对象中字符的处理

我们经常要对 string 对象中的单个字符进行处理,例如,通常需要知道某个特殊字符是否为空白字符、字母或数字。下表列出了各种字符操作函数,适用于 string 对象的字符(或其他任何 char 值)。这些函数都在 cctype 头文件中定义。

isalnum(c) 如果 c 是字母或数字,则为 True。
isalpha(c) 如果 c 是字母,则为 true。
iscntrl(c) 如果 c 是控制字符,则为 true
isdigit(c) 如果 c 是数字,则为 true。
isgraph(c) 如果 c 不是空格,但可打印,则为 true。
islower(c) 如果 c 是小写字母,则为 true。
isprint(c) 如果 c 是可打印的字符,则为 true。
ispunct(c) 如果 c 是标点符号,则 true。
isspace(c) 如果 c 是空白字符,则为 true。
isupper(c) 如果 c 是大写字母,则 true。
isxdigit(c) 如果是 c 十六进制数,则为 true。
tolower(c) 如果 c 大写字母,返回其小写字母形式,否则直接返回 c。
toupper(c) 如果 c 是小写字母,

表中的大部分函数是测试一个给定的字符是否符合条件,并返回一个 int 作为真值。如果测试失败,则该函数返回 0 ,否则返回一个(无意义的)非 0 ,表示被测字符符合条件。
表中的这些函数,可打印的字符是指那些可以表示的字符,空白字符则是空格、制表符、垂直制表符、回车符、换行符和进纸符中的任意一种;标点符号则是除了数字、字母或(可打印的)空白字符(如空格)以外的其他可打印字符。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/fan_xingwang/article/details/82842575

智能推荐

redhat6.3 安装yum命令_wexin_bai750259172的博客-程序员秘密

RHEL6解决无法使用YUM源问题RHEL的YUM源需要注册用户才能更新使用,由于CentOS和RHEL基本没有区别,并且CentOS已经被REHL收购。所以将RHEL的YUM源替换为CentOS即可。问题如下:[[email protected] ~]# yum repolistLoaded plugins: product-id, refresh-packagekit, security,

MFC架构之CObject类_FlowShell的博客-程序员秘密

<br />      CObject是大多数MFC类的根类或基类。CObject类有很多有用的特性:对运行时类信息的支持,对动态创建的支持,对串行化的支持,对象诊断输出,等等。MFC从CObject派生出许多类,具备其中的一个或者多个特性。程序员也可以从CObject类派生出自己的类,利用CObject类的这些特性。<br />     本文讨论MFC如何设计CObject类的这些特性。首先,考察CObject类的定义,分析其结构和方法(成员变量和成员函数)对CObject特性的支持。然后,讨论CObje

二进制数的原码反码与补码_weixin_30410999的博客-程序员秘密

众所周知,二进制是我们计算机语法的基本组成,他以0和1为基础,构建了我们多样神奇的信息世界。因此说,二进制对于我们是十分重要的。对于二进制来说,他在计算机中有三中表示方法:原码、反码和补码。这三种码的区别,就是对于正负表示不同的区别。对于原码来说,他对于正负的表示方法是在整个二进制数前加0或1。0用来表示正号,1用来表示负号。比如,一个正二进制数+1101表示为01101,负二...

5G-SUPI-SUPC-IMSI_imsi supi_weixin_37646183的博客-程序员秘密

0x00 IMSI &amp; IMSI-Catcher我们以前担心的手机泄漏个人位置隐私的问题,也就是在2G/3G/4G一直存在的IMSI Catcher问题,终于有望在5G标准里得到彻底解决啦! 这个问题在每次制定新一代网络标准的时候,都要争论一回。这是网络功能性、成本与安全性之间的斗争。在5G的第一版标准,Release15,关于安全的标准[1]中,IMSI加密是最大的亮点。在2/3/4...

计算机应用技术作业,计算机应用与技术-作业题.doc_weixin_39747630的博客-程序员秘密

文档介绍:计算机应用与技术网上作业题第一部分计算机基础知识作业题一、选择题1.第二代电子计算机使用的电子器件是____。A)电子管B)晶体管C)集成电路D)超大规模集成电路2.计算机病毒是指____。A)带细菌的磁盘B)已损坏的磁盘C)具有破坏性的特制程序D)被破坏的程序3.与十六进制数AB等值的十进制数是____。A)175B)176C)177D)1714.计算机中所有信息的存储都采用____。...

随便推点

OpenCV 实现读取USB摄像头数据,并旋转90度显示_usbcamera.cpp旋转摄像头_不解不惑的博客-程序员秘密

实现图像的选装的方法有很多,如果是旋转90,180,270度这种,没必要采用透视变换之类的运算,采用矩阵转置之列的就好,当然也可以采用挨个像素的搬运,那样的话,需要更长的时间调试代码,属于细节的问题,产品落地的时候才有必要关心。#include &lt;iostream&gt;#include &lt;opencv2/core/core.hpp&gt;#include &lt;open...

C++读取文件统计单词个数及频率_普通网友的博客-程序员秘密

1.Github链接GitHub链接地址https://github.com/Zzwenm/PersonProject-C22.PSP表格PSP2.1Personal Software Process Stages预估耗时(分钟)实际耗时(分钟)Planning计划• Estimate• 估计这个任务需要多少时间480720Develo...

K8S 查看 Pod 日志_查看pod日志_catoop的博客-程序员秘密

如果容器已经崩溃停止,您可以仍然使用 kubectl logs --previous 获取该容器的日志,只不过需要添加参数 --previous。 如果 Pod 中包含多个容器,而您想要看其中某一个容器的日志,那么请在命令的最后增加容器名字作为参数。# 追踪名称空间 nsA 下容器组 pod1 的日志kubectl logs -f pod1 -n nsA# 追踪名称空间 nsA 下容器组 pod1 中容器 container1 的日志kubectl logs -f pod1 -c containe

python-opencv--高斯模糊_小蜗牛的博客的博客-程序员秘密

import cv2 as cvimport numpy as npdef clamp(pv):if pv &gt; 255:return 255if pv &lt; 0:return 0else:return pvdef gaussian_noise(image): #直接是在每个通道添加随机的数值h, w, c = image.shapefor row in range(h):for col in range(w):s = np.random.normal(0, 20, 3)

常见激光雷达分类_光学测距的单点和面阵的区别_阿木实验室的博客-程序员秘密

一、激光雷达的原理激光雷达的原理类似于声呐,只不过这里我们用光代替声音,来衡量激光雷达与障碍物之间的距离。主要工作原理是向目标发射激光束(单线/多线),然后将反射信号与发射信号比较, 分析信号的折返时间(TOF)或频率差(多普勒频移),即可获得目标距离等相关参数。为什么叫激光雷达?激光是大量原子受激辐射所产生的发光行为,激光在传播中始终像一条笔直的细线,发散的角度极小。如果一个激光雷达能够在同一个空间内,按照设定好的角度发射无数条激光,就能得到无数基于障碍物的反射信号。比如一条线..

计算机图形学实验一中点算法绘制圆_利用中点扫描算法,对单位圆进行绘制_机器王德发的博客-程序员秘密

java实现计算机图形学中点画圆算法计算机图形学实验一采用中点画圆算法原理绘制1/8圆弧,然后利用圆的高度对称性,基于java的Graphics类,调用getGraphics()方法,在GUI界面上绘图,由于java的坐标位于左上角,所以我们可以将圆心移动至面板中心再进行算法进程:...

推荐文章

热门文章

相关标签