C++ Primer笔记 Chapter3 之标准库类型string

命名空间的using声明和标准库类型string

命名空间的using声明

using声明的形式

using namespace::name;

Code Example:

#include<iostream>
using std::cin;
int main()
{

	int i;
	cin >> i;
	cout << i;//错误:没有对应的using声明,必须使用完整的名字 std::cout
	std::cout << i;//正确:显式地从std中使用cout


	return 0;
}

每个名字都需要独立的using声明

​ 每个using声明引入命名空间中的一个成员

Code Example:

#include<iostream>
using std::cin;

//每个using声明引入命名空间中的一个成员
using std::cout; using std::endl;
int main()
{
	cout << "Enter two number:" << endl;
	int v1, v2;
	cin >> v1 >> v2;
	cout << "The sum of " << v1 << " and " << v2
		<< " is " << v1 + v2 << endl;

	return 0;
}

头文件不应包含using声明

​ 位于头文件的代码一般来说不应该使用using声明。因为头文件里包含了using声明,那么使用该头文件的文件就都会有这个声明,可能会产生名字冲突

标准库类型string

​ 标准库类型string —可变长的字符序列,使用string类型需包含string头文件,作为标准库的一部分,string定义在命名空间std中

#include<string>
using std::string;

定义和初始化string对象

初始化String对象的方式
语句功能
string s1默认初始化,s1是一个空串
string s2(s1)s2是s1的副本
string s2 = s1等价于s2(s1) , s2是s1的副本
string s3(“value”)s3是字面值”value“的副本,除了字面值最后的那个空字符外
string s3 = “value”等价于s3(“value”), s3是字面值”value“的副本
string s4(n,‘c’)把s4初始化为由连续n个字符c组成的串

拷贝初始化:使用=来初始化一个变量,编译器把等号右侧的初始值拷贝到新创建的对象中。

直接初始化:不使用等号

​ 初始值只有一个时,拷贝初始化和直接初始化都可以,当初始化要用到的值有多个,一般只能使用直接初始化

string s5 = "hiya";//拷贝初始化
string s6("hiya");//直接初始化
string s7(10,'c');//直接初始化,s7的内容是cccccccccc

多值进行初始化的时候,也可以用拷贝初始化但需显式的创建一个(临时)对象用于拷贝:

(不建议麻烦,可读性差,无任何补偿优势)

string s8 = string(10,'c');//拷贝初始化
//相当于以下代码
string temp(10,'c');
string s8 = temp;

string对象上的操作

string的操作
语句功能
os<<s将s写到输出流os当中,返回os
is>>s从is中读取字符串赋给s,字符串以空白分隔,返回is
getline(is,s)从is中读取一行赋给s,返回is
s.empty()s为空返回true,否则返回false
s.size()返回s中字符的个数
s[n]返回s中的n个字符的引用,位置n从0计起
s1+s2返回s1和s2连接后的结果
s1=s2用s2的副本代替s1中原来的字符
s1==s2若s1和s2中所含的字符完全一样,则它们相等;大小写敏感
s1!=s2若s1和s2中所含的字符完全一样,则它们相等;大小写敏感
<、<=、>、>=利用字符在字典中的顺序进行比较,且对字母的大小写敏感
读写string对象

可以使用IO操作符读写string对象

string s;//空字符串
cin>>s;//将string对象读入s,遇到空白停止
cout<<s<<endl;//输出s

读取操作时,string对象自动忽略开头的空白(即空格符、换行符、制表符等)并从第一个真正的字符开始读起,直到遇见下一处空白为止

读取未知数量的string对象
string word;
while (cin>>word)//反复读取,直至到达文件末尾
{
	cout << word << endl;//逐个输出单词,每个单词后面紧跟一个换行
}

while语句的条件部分负责在读取时检测流的情况,若流有效,即没遇到文件结束标记或非法输入,则执行while语句内部的操作。一旦遇到文件结束标记或非法输入,循环结束

使用getline读取一整行

希望保留输入时的空白符则应该使用getline函数 ,getline()的参数是一个输入流和一个string对象。

从给定的输入流中读入内容,直到遇到换行符为止(换行符也被读入了),把所读的内容存入到string对象中(不存换行符)。

一遇到换行符就结束读取操作并返回结果,即使是一开始就是换行符。若输入一开始就是换行符,则所得结果是个空string

和输入运算符一样,getline也会返回它的流参数,故getline的结果也可作为条件

string line;
//每次读入一整行,直至到达文件末尾
while(getline(cin,line))
    cout<<line<<endl;

endl结束当前行并刷新显示缓冲区

Note:

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

string的emty和size操作

empty函数根据string对象是否为空返回一个对应的布尔值,是string的一个成员函数,使用点操作符调用

string line1;
while (getline(cin,line1))
{
	if (!line1.empty())
	{
		cout << line1 << endl;
	}
}

!为逻辑非运算符,返回与其运算对象相反的结果

size函数返回string对象的长度(即string对象中字符的个数)

string line2;
while (getline(cin, line2))//只输出长度超过80个字符的长度
{
	if (line2.size()>80)
	{
		cout << line2 << endl;
	}
}
string::size_type类型

size()函数返回的是一个string::size_type类型的值,

string::size_type是一个无符号类型的值,而且能够存下任何string对象的大小。

通过作用域操作符表明size_type是在类string中定义的

所有用于存放string类的size函数返回值的变量都应该是string::size_type类型的

C++11中,允许编译器通过auto或者decltype来推断变量的类型

auto len = line.size();//len的类型是string::size_type

size函数返回的是一个无符号整型数,如果一条表达式中已经有了size()函数就不要在使用int了(表达式中混用了带符号数和无符号数将可能产生意想不到的结果

比较string对象

比较运算符逐一比较string对象中的字符,并且对大小写敏感

==和!=相等性运算符检验两个string对象相等或不相等,string对象相等:长度相同且所包含的字符也全都相同。

<、<=、>、>=关系运算符分别检验一个string对象是否小于、小于等于、大于、大于等于另一个string对象 依照(大小写敏感)字典顺序

  1. 两个string对象长度不同,且较短string对象的每个字符都与较长string对象对应位置上的字符相同,则较短string对象小于较长string对象
  2. 两个string对象在某些对应位置上不一致,则string对象比较的结果其实是string对象中第一对相异字符比较的结果
string str = "Hello";
string phrase = "Hello World";
string slang = "Hiya";

结果:str小于phrase (规则1判断),slang比str、phrase都大(规则2判断)

为string对象赋值

允许把一个对象的值赋给另一个对象:

string st1(10,'c'), st2;
st2 = st1;//赋值:用st2的副本替换st1的内容
//both st1 and st2 are null string
两个string对象相加

对string对象使用加号运算符 +的结果是一个新的string对象。它由加号左侧string所含的字符与右侧string所含的字符拼接而成。

复合运算符+=负责把右侧string对象的内容追加到左侧string对象的后面

string s1 = "hello, ", s2 = "world\n";
string s3 = s1 + s2;//s3的内容是hello, world\n
s1 += s2;//等价于s1 = s1 + s2
字面值和string对象相加

标准库允许把字符字面值和字符串字面值转换成string对象,
故在需要string对象的地方可以使用它们来替代

string sss1 = "hello", sss2 = "world";
string sss3 = sss1 + "," + sss2 + '\n';	

必须确保每个加法运算符的两侧的运算对象至少有一个是string


string s4 = s1 + ",";//正确,存在至少一个string

string s5 = "hello" + ",";//错误:两个运算对象都不是string

string s6 = s1 + "," + "world";
//正确:相当于string s6=(s1+",")+"world";

string s7 = "hello" + "," + s2;
//error,相当于s7=("hello"+",")+s2;  不能字面值直接相加

字符串字面值与string是不同的类型

处理string中的字符

cctype头文件中的函数

函数作用
isalnum( c )当c是字母或数字是为真
isalpha( c )当c是字母时为真
iscntrl( c )当c是控制字符时为真
isdigit( c )当c是数字时为真
isgraph( c )当c不是空格但可打印时为真
islower( c )当c是小写字母时为真
isprint( c )当c是可打印字符时为真(即c是空格或c具有可视形式)
ispunct( c )当c是标点符号时为真(即c不是字母、数字、字母、可打印空白中的一种)
isspace( c )当c时空白时为真(即c时空格、横向制表符,纵向制表符、回车符、换行符、进纸符中的一种)
issupper ( c )当c是大写字母时为真
isxdigit( c )当c是十六进制数字时为真
tolower( c )如果c是大写字母,输出对应的小写字母:否则原样输出c
toupper( c )如果c是小写字母,输出对应的大写字母:否则原样输出c
	C语言中的头文件形如:name.h,C++则将这些文件命名为cname
	特别的,cname的头文件中定义的文字从属于std,而定义在名为.h的头文件的则不然
	标准库中的名字总能在std中找到       
处理每个字符 使用基于范围的for语句

范围for(range for)语句(C++11):遍历给定序列中的每个元素并对序列中的每个值执行某种操作

for(declaration:expression)
    statement

expression是一个对象,表示一个序列

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

一个string对象表示一个字符的序列,故string对象可作为范围for语句中的expression部分

string str("some string");
for (auto c : str)
	cout << c << endl;

此处通过auto让编译器决定c的类型,此处c的类型是char

范围for语句和ispunct()统计标点符号数

string s("Hello World!!!");
//punct_cnt类型和s.size的返回类型一样即string::size_type,是一个无符号类型的值
decltype(s.size()) punct_cnt = 0;//标点符号计数值
for(auto c:s)
	if (ispunct(c))
	{
		++punct_cnt;
	}
cout << punct_cnt << " punctuation characters in " << s << endl;

此处使用decltype声明punct_cnt,类型为string::size_type

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

若想改变string对象中字符的值,必须把循环变量定义成引用类型,当使用引用作为循环控制变量时,这个变量实际上被依次绑定到了序列的每个元素上。使用这个引用,就能改变它绑定的字符

把字符串改写为大写字母的形式

string s("Hello World!!!");	
for (auto& c : s)
	c = toupper(c);
cout << s << endl;
只处理一部分字符

访问string对象中的单个字符有两个方式:

  1. 使用下标
  2. 使用迭代器

下标运算符[]接收的输入参数是string::size_type类型的值,这个参数表示要访问的字符的位置:返回值是该位置上字符的引用

string对象的下标从0计起 ,s[s.size()-1]是最后一个字符

string对象的下标必须大于等于0而小于s.size()

使用下标访问空string会引发不可预知的结果

下标的值称:“下标” 或 “索引” ,任何表达式只要它的值是一个整型值就能作为索引,若某个索引是带符号类型的值将自动转换成由string::size_type表达的无符号类型

//判空操作
if (!s.empty())
{
    cout << s[0] << endl;
}

只要对string对象使用了下标,都要确定在那个位置上确实有值,s为空,则s[0]的结果将是未定义的

只要字符串不是常量,就能为下标运算符返回的字符赋新值

//判空并对第一个字符改为大写形式
string s1("some string");
if (!s1.empty())
{
    s[0] = toupper(s[0]);
}
cout << s1 << endl;

输出结果:

Some string
使用下标执行迭代
//把s1的第一个词改成大写形式
//依次处理s1中的字符直至我们处理完全部字符或遇到一个空白
for (decltype(s1.size()) index = 0; index!=s1.size()&&!isspace(s1[index]); ++index)
{
    s1[index] = toupper(s1[index]);//将当前字符改成大写形式
}
cout << s1 << endl;
逻辑与运算符&&

规则:参与运算的两个运算对象都为真,则逻辑与结果为真,否则为假

只有当左侧运算对象为真时才会检查右侧运算对象

Tip

下标必须大于等于0而小于字符串的 size() 的值,
简便易行的方法是:总是设下标的类型为 string::size_type。
因为此类型是无符号数,可确保下标不会小于 0,
此时只需保证下标小于 size() 的值
使用下标执行随机访问

例:把0~15之间的十进制数转换成对应的十六进制数,只需初始化一个字符串令其存放16个十六进制"数字"

const string hexdigits = "0123456789ABCDEF";
cout << "Enter a series of number between 0 and 15" << endl;
string result;//此时还是空字符串
string::size_type n;//用于保存从输入流读取的数
while (cin>>n)
{
	if (n<hexdigits.size())
		{
			result += hexdigits[n];//得到相应的十六进制数字
		}
}
cout << result << endl;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值