3.2标准库类型string


标准库类型string表示可变长的字符序列,使用string类型的时候建议先加上string的头文件,string的定义也在命名空间std当中。

定义和初始化string对象

如何初始化类的对象是由类本身决定的,一个类可以定义很多种初始化对象的方式,只不过这些方式之间必须有所区别,或者是初始值不同,或者是初始值的类型不同。下面是初始化string的最常用的一些方式:

string s1; //1
string s2=s1;//2
string s3=“hi”;//3
string s4(10,‘c’);//4
string s5(“hi”);//5

  1. 默认初始化,s1是一个空字符串
  2. s2是s1的副本
  3. s3是指向该字符串字面值的副本
  4. s4的内容是cccccccccc
  5. s5与s3相同,是指向该字符串字面值的副本

直接初始化和拷贝初始化

由之前的学习中,我们明白了如果使用=初始化一个变量,实际上就是执行拷贝初始化,编译器把等号右侧的初始值拷贝到新创建的对象中去。与之相反,如果不适用等号,则执行的是直接初始化

对于初始值只有一个的时候,使用直接 初始化或者拷贝初始化没有什么区别:

string s3=“hi”;//直接初始化
string s5(“hi”);//拷贝初始化
string s4(10,‘c’);//直接初始化

而对于多个值进行初始化的时候,可以使用直接初始化,也可以使用拷贝初始化,但是需要一个暂时的类进行储存,之后也会经常用到。

string s6 = string(10,‘c’);//拷贝初始化,
里面的内容是cccccccccc

string对象上的操作

一个类除了要规定初始化其对象的方式以外,还要定义对象上所能执行的操作。其中,类既能定义通过函数名调用的操作,也能定义<<,+等各种运算符在该类对象上的新含义。以下是string上的大多数操作。

os<<s;//1
is>>s;//2
getline(is,s);//3
s.empty()//4
s.size();//5
s{n};//6
s1+s2;//7
s1=s2;//8
s1==s2//9
s1!=s2//10
<、<=、>、>=//11

  1. 将s写道输出流os当中,返回os
  2. 从is中读取字符串赋值给s,字符串以空白分割,返回is
  3. 从is中读取一行赋值给s,返回is
  4. s为空返回true,否则返回false
  5. 返回s中字符的个数,不包括’\0’
  6. 返回s中第n个字符的引用,位置n从0开始计起
  7. 返回s1和s2连接的结果
  8. 用s2的副本代替s1中原来的字符
  9. 如果s1和s2中所含的字符全都一致,则他们相等
  10. 不一致则不相等
  11. 利用字符在字典中的顺序进行比较,且对字母的大小写敏感

读写string对象

#include<iostream>
#include<string>
using namespace std;

int main()
{
	string s;         //空字符串
	cin >> s;         //将string对象读入s,遇到空白(回车和空格)停止
	cout << s << endl;//输出s
	return 0;
}

这段程序首先定义了一个名为s的空string,然后将标准输入的内容读取到s中,在执行读取操作的时候,string对象会自动忽略开头的空白(即空格符,换行符,制表符)并从第一个真正的字符开始读起,直至遇见下一个空白为止。

而如果我们向输入流输入" Hello World “的时候,输出将是"Hello”,输出结果中将没有任何空格。

读取未知量的string对象

这里仅给出代码部分,相信大家也可以轻松看懂。

#include<iostream>
#include<string>
using namespace std;

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

使用getline读取一整行

有时候我们希望可以在最终得到的字符串中保留输入时的空白符,这时候应该使用getline函数替代原本的>>运算符。getline函数的参数是一个输入流和一个string对象,函数从给定义的输入流中读取内容,直至换行符为止,然后把所读的所有内容存入那个string函数当中去。getline只要一遇到换行符就结束读取操作并返回结果,哪怕输出的一开始就只是一个换行符(空)。

如我们也可以使用getline让上面的代码一次性输出一整行

#include<iostream>
#include<string>
using namespace std;

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

PS:触发getline函数返回的那个换行符实际上被丢弃掉了,得到的string对象中并不包含换行符

string的empty和size操作

empty作为string内部的一个函数,顾名思义,它就是判断string类型变量内部的数值是否为空,若为空返回true否则返回false的一个函数下面给出相关使用的代码:

#include<iostream>
#include<string>
using namespace std;

int main()
{
	string str;
	while (getline(cin, str))
		if(!str.empty())
			cout << str << endl;
	return 0;
}

size函数则是返回string对象的长度,见代码,不赘述

#include<iostream>
#include<string>
using namespace std;

int main()
{
	string str;
	while (getline(cin, str))
		if(str.size()>0)
			cout << str << endl;
	return 0;
}

string::size_type类型

string::size_type也就是常说的size_t类型,这里找到size函数的定义size_t size() const;以下是对于size_t的介绍

size_t是一个无符号类型的整数值,这是毋庸置疑的,因为没有字符串是-1个的是吧

所以我们在使用这个数据进行比较的时候,切记如果将其和负数的int进行比较,将会出错,具体原因可见之前的文章,这里不赘述。

比较string对象

string类定义了几种用于比较字符串的运算符。这些比较运算符逐一比较string对象中的字符,并且对大小写敏感。这里的比较一般是以字典的顺序来进行比较的。

举个例子进行理解

string str1 = “Hello”;
string str2 = “Hello World”
string str3 = “Hiya”

比较的顺序是按照字母的顺序来进行比较的,比较不相同的第一位,故str1和str2进行比较的话,str2大于str1,str3大于str1,str2;

为string对象赋值

允许用=号进行赋值,故:

string str1(10,‘c’),str2;
str2=str1;

两个string对象相加

两个string对象相加得到一个新的string对象,其内容是把左侧的运算对象与右侧的运算对象串联而成。

#include<iostream>
#include<string>
using namespace std;

int main()
{
	string str1="hello ", str2="world\n", str3;
	str3 = str1 + str2;
	str1 += str2;
	cout << str3 << str1;
	return 0;
}

应该也可以很简单的看懂吧,自行判断一下各自的值。

字面值和string对象相加

#include<iostream>
#include<string>
using namespace std;

int main()
{
	string s1 = "hello", s2 = "world";//1
	string s3 = s1 + "," + s2 + '\n';//2
	string s4 = s1 + ",";//3
	string s5 = "hello" + ",";//4
	string s6 = s1 + "," + "world";//5
	string s7 = "hello" + "," + s2;//6
	return 0;
}
  1. 定义成string类型
  2. 正确用法
  3. 正确,把一个string对象和一个字面值进行相加
  4. 错误,两个对象都是字面值,相加的结果也还是字面值,不为string类型,类型不匹配。
  5. 正确,每个加法运算符都由一个运算对象是string。
  6. 错误,根据运算顺序可得,中间又一步骤是将两个字面值进行相加。

处理string对象的字符

我们经常要单独处理string对象中的字符,这在一头文件中由定义许多相关的函数

#include<cctype>

下面列出常用的函数:

isalnum( c );//1
isalpha( c );//2
iscntrl( c );//3
isdigit( c );//4
isgraph( c );//5
islower( c );//6
isprint( c );//7
ispunct( c );//8
ispace( c );//9
isupper( c );//10
isxdigit( c );//11
tolower( c );//12
toupper( c );//13

  1. 当c是字母或者数字的时候为真
  2. 当c是字母的时候为真
  3. 当c是控制字符是为真
  4. 当c是数字的时候为真
  5. 当c不是空格但可以打印的时候为真
  6. 当c是小写字母的时候为真
  7. 当c是可打印字符是为真
  8. 当c是空白时为真
  9. 当c是大写字母的时候为真
  10. 当c是十六进制时为真
  11. 如果c是大写字母,则输出对应的小写字母,否则原样输出c
  12. 如果c是小写字母,则输出对应的大写字母,否则原样输出c

处理每一个字符,使用基于范围的for语句

范围for语句的表达式

for(declaration:expression)
statement

其中expression部分是一个对象,用于表示一个序列。declaration部分负责定义一个变量,该变量将被用于访问序列中的基础元素。每次迭代,declaration部分的变量就会被初始化为expression部分的下一个元素值。

例如:

#include<iostream>
#include<string>
#include<cctype>
using namespace std;

int main()
{
	string str("some string");
	for (char c: str)
	{
		cout << c << endl;
	}
	return 0;
}

这个例子相信大家也可以更好的理解范围for的用法了。举个稍微复杂的例子。

#include<iostream>
#include<string>
#include<cctype>
using namespace std;

int main()
{
	string str("Hello,World!!");
	decltype(str.size()) punct_num = 0;
	for (char c : str)
		if (ispunct(c))
			punct_num++;
	cout << punct_num;
	return 0;
}

这是统计标点符号的个数的函数,大家可以理解一下,也很好理解。

使用范围for语句改变字符串中的字符

这里写一个把字符串改编成其大写类型的具体函数

#include<iostream>
#include<string>
#include<cctype>
using namespace std;

int main()
{
	string str("Hello,World!!");
	for (auto c : str)
		c = toupper(c);
	cout << str;
	return 0;
}

这里有一个切记的就是一定要记住auto c后面是==:==而非=。

只处理一部分字符

如果要处理string内部的所有字符,范围for语句确实是一个好主意,但是我们有时候要访问的是部分,则不太好用了。

一般是有两种方法进行处理:

第一种:下标运算符,要注意的是string类型是从第0位开始的,所以最后一位是str[str.size()-1]

PS:string对象的下标必须大于等于0,而小于str.size()如果超出这个范围将造成不可预知的错误,以此判断,用下标法访问空string类型也将产生不可预知的后果。

#include<iostream>
#include<string>
#include<cctype>
using namespace std;

int main()
{
	string str("hello,World!!");
	if (!str.empty())
		str[0] = toupper(str[0]);
	cout << str;
	return 0;
}

第二种方法是使用迭代器,后续再进行介绍。

使用下标执行迭代

#include<iostream>
#include<string>
#include<cctype>
using namespace std;

int main()
{
	string str("hello World!!");
	for (decltype(str.size()) index = 0; index != str.size() && !isspace(str[index]); index++)
	{
		str[index] = toupper(str[index]);
	}
	cout << str;
	return 0;
}

这里可以停顿调试理解一下。也就是之前综合的知识。

使用下标执行随机访问

这里也是一段函数仅供理解,题目是将0-15的数据转换为16进制数。

#include<iostream>
#include<string>
#include<cctype>
using namespace std;

int main()
{
	const string hex = "0123456789ABCDEF";
	string str;
	int num;
	while (cin >> num)
		if (num < hex.size() && num >= 0)
			str += hex[num];
	cout << str;
	return 0;
}

如果是读者复制了代码准备调试时,切记要输入一个crtl+z原因就在于cin>>num放于while内,此符号声明读取结束。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值