C++ Primer Plus 学习笔记
第 6 章 分支语句和逻辑运算符
if 语句
if (test-condition)
statement
整个if
语句被视为一条语句。
if else 语句
if (test-condition)
statement1
else
statement2
整个if else
结构被视为一条语句。
if else if else 语句
if (test-condition)
statement1
else
if (test-condition)
statement2
else
statement3
if (test-condition)
statement1
else if (test-condition)
statement2
else
statement3
条件运算符和错误防范
许多程序员将更直观的表达式variable == value
反转为value == varialbe
,以此来捕获将相等运算符误写为赋值运算符的错误。
逻辑表达式
C++ 提供了 3 种逻辑运算符,分别是逻辑 OR||
、逻辑 AND&&
、逻辑 NOT!
。
逻辑 OR 运算符:||
expr1 || expr2 的值
… | expr1 == true | expt1 == false |
---|---|---|
expr2 == true | true | true |
expr2 == false | true | false |
||
的优先级比关系运算符低。
C++ 规定,||
运算符是个顺序点。
逻辑 AND 运算符:&&
expr1 && expr2 的值
… | expr1 == true | expt1 == false |
---|---|---|
expr2 == true | true | false |
expr2 == false | false | false |
&&
的优先级比关系运算符低。
C++ 规定,&&
运算符也是个顺序点。
逻辑 NOT 运算符:!
!
运算符将它后面的表达式的值取反。对于返回true-false
值或可以解释为true-false
值的函数来说很有用。
逻辑运算符细节
C++ 逻辑 OR 和逻辑 AND 运算符的优先级都低于关系运算符。
逻辑 NOT 运算符的优先级高于所有的关系运算符和算术运算符。
逻辑 AND 运算符的优先级高于逻辑 OR 运算符。
虽然 C++ 运算符的优先级规则常可能不使用括号便可以编写复合比较的语句,但最简单的方法还是用括号将测试进行分组,而不管是否需要括号。这样代码容易阅读,避免读者查看不常使用的优先级规则,并减少由于没有准确记住所使的规则而出错的可能性。
C++ 确保程序从左向右进行计算逻辑表达式,并在知道答案后立刻停止。
其他表示方式
标识符and
、or
和not
都是 C++ 保留字,这意味着不能将它们用作变量名等。它们不是关键字,因为它们都是已有语言特性的另一种表示方式。另外,它们并不是 C 语言中的保留字,但语言程序可以将它们用作运算符,只要在程序中包含了头文件iso646.h
。C++ 不要求使用头文件。
运算符 | 另一种表示方式 |
---|---|
&& | and |
|| | or |
! | not |
字符函数库 cctype
C++ 从 C 语言继承了一个字符函数库,原型在关文件cctype
(老式的风格中为ctype.h
)中定义。(这些函数返回的类型为int
,而不是bool
,但通常类型转换可视为是bool
类型。)
cctype 中的字符函数
函数名称 | 返回值 |
---|---|
isalnum() | 如果参数是字母数字,即字母或数字,该函数返回 true |
isalpha() | 如果参数是字母,该函数返回 true |
iscntrl() | 如果参数是控制字符,该函数返回 true |
isdigit() | 如果参数是数字(0~9),该函数返回 true |
isgraph() | 如果参数是除空格之外的打印字符,该函数返回 true |
islower() | 如果参数是小写字母,该函数返回 tnue |
isprint() | 如果参数是打印字符(包括空格),该函数返回 true |
ispunct() | 如果参数是标点符号:该函数返回truc |
isspace() | 如果参数是标准空白字符:如空格、进纸、换行符、回车、水平制表符或者垂直制表符,该函数返回 true |
isupper() | 如果参数是大写字母,该函数返问 truc |
isxdigit() | 如果参数是十六进制数字,即 0~9、a~f 或 A~F,该函数返回 true |
tolower() | 如果参数是大写字符,则返回其小写,否则返回该参数 |
toupper() | 如果参数是小写字符,则返回其大写,否则返回该参数 |
?:运算符
C++ 有一个常被用来代替if else
语句的运算符,被称为条件运算符?:
,它是 C++ 中唯一一个需要 3 个操作数的运算符。该运算符的通用格式如下:
expression1 ? expression2 : expression3
如果expression1
为ture
,则整个表达式的值为expression2
的值,否则,为expression3
的值。
int c = a > b ? a : b;
\\与下面语句等效
int c;
if (a > b)
c = a;
else
c = b;
与if else
序列相比,条件运算符更简洁。两种方法之间的区别是,条件运算符生成一个表达式,因此是一个值,可以将其赋给变量或将其放到一个更大的表达式中。其中一个技巧(它完成一个应被谴责的任务——隐藏代码)是将条件表达式嵌套在另一个条件表达式中:
const char x[2][20] = {"Jason", "at your service\n"};
const char * y = "Quillstone";
for (int i = 0; i < 3; i++)
cout << ((i < 2) ? !i ? x[i] : y : x[1]);
\\print
Jason Quillstone at your service.
从可读性来说,条件运算符最适合于简单关系和简单表达式的值。
switch 语句
C++ 的switch
语句能够更容易从大型列表中进行选择。通用格式如下:
switch (integer-expression)
{
case label1 : statement(s)
case label2 : statement(s)
...
default : statement(s)
}
integer-expression
必须是一个结果为整数值的表达式,每个标签都必须是整数常量表达式,最常见的标签是int
和char
常量(如1
或q
),也可以是枚举量。如果integer-expression
不与任何标签匹配,则程序跳到default
那一行,default
标签是可选的,如果被省略,而又没有匹配的标签,则程序将跳到switch
后面的语句处。
C++ 中的case
标签只是行标,而不是选项之间的界线。程序跳到特定行后,将依次执行这后的所有代码,不会执行到一下case
处自动停止,因此,必须使用break
语句让程序跳到switch
后面的语句处执行。这样做的好处是可以使用多个标签。
将枚举量用作标签
当switch
语句将int
值与枚举量标签进行比较时,将枚举量提升为int
。另外,在while
循环测试条件中,也会将枚举量提升为int
类型。
switch 和 if else
如果选项涉及聚会范围、浮点测试或两个变量的比较,则应使用if else
语句。
如果既可以使用if else if
语句,也可以使用switch
语句,则当选项不少于 3 个时,应使用switch
语句,因为如果选项超过两个,应代码长度和执行速度而言,switch
语句的效率更高。
break 和 continue 语句
break
语句使用程序跳到switch
或循环后面的语句处执行,continue
语句让程序跳过循环体中余下的代码,并开始新一轮循环。
和 C 语言一样,C++ 也有goto
语句,可以使用程序跳到指定标签处,但在大多数情况下(有人认为在任何情况下),使用goto
语句不好,而应使用结构化控制语句(如if else``switch``continue
等)来控制程序的流程。
读取数字的循环
假设要编写一个将一系列数字读入到数组中的程序,并允许用户在数组填满之前结束输入。一种方法
是利用cin
,如果用户输入一个单词,一而不是一个数字,将发生4种情况:
- 数组值不变;
- 不匹配的输入将被留在输入队列中;
cin
对象中的一个错误标记被设置;- 对
cin
方法的调用将返回false
(如果被转换为bool类
型)。
方法返回false
意味着可以用非数字输入来结束读取数字的循环。非数字输入设置错误标记意味着必须重置该标记,程序才能继续读取输入。clear()
方法重置错误输入标记,同时也重置文件尾(EOF)条件。输入错误和 EOF 都将导致cin
返回false
。
cin >> n
实际上是一个cin
方法函数调用,该函数返回cin
。如果cin
位于测试条件中,则将被转换成bool
类型,如果输入成功则转换后的值为true
,否则为false
。
如果需要提示错误后需要继续输入数字,应采取 3 个步骤:
- 重置
cin
以接受新的输入; - 删除错误的输入;
- 提示重新输入。
简单的文件输入/输出
C++ 使得将读取键盘输入和屏幕输出(统称为控制台输入/输出)的技巧用于文件输入/输出(文件 I/O)。
文件 I/O 和文本文件
使用cin
进行输入时,程序将输入视为一系列的字节,其中每个字节都被解释为字符编码。不管目标数据类型是什么,输入一开始都是字符数据——文本数据。然后cin
对象负责将文本转换为其他类型。
假设有如下示例输入行:
38.5 19.2
使用不同数据类型的变量来存储时,cin
是如何处理该输入行的。
char ch;
cin >> ch;
输入行中的第一个字符被赋给ch。在这里,第一个字符是数字3
,其字符编码(二进制)被存储在变
量ch
中。输入和目标变量都是字符,因此不需要进行转换。执行上述输入语句后,输入队列中的下一个字符为字符8
,下一个输入操作将对其进行处理。
int n;
cin >n;
在这种情况下,cin
将不断读取,直到遇到非数字字符。也就是说,它将读取3
和8
,这样句点将成为输入队列中的下一个字符。cin
通过计算发现,这两个字符对应数值38
,因此将38
的二进制编码复制到变量n
中。
double x;
cin >> x;
在这种情况下,cin
将不断读取,直到遇到第一个不属于浮点数的字符。也就是说,cin
读取3
、8
、.
和5
,使得空格成为输入队列中的下一个字符。cin
通过计算发现,这四个字符对应于数值38.5
,因此将38.5
的二进制编码(浮点格式)复制到变量x
中。
char word[50];
cin >> word;
在这种情况下,cin
将不断读取,直到遇到空白字符。也就是说,它读取3
、8
、.
和5
,使得空格成为输入队列中的下一个字符。然后,cin
将这 4 个字符的字符编码存储到数组word
中,并在末尾加上一个空字符。这里不需要进行任何转换。
char word[50];
cin.getline(word, 50);
在这种情况下,cin
将不断读取,直到遇到换行符(示例输入行少于50个字符)。所有字符都将被存储到数组word
中,并在末尾加上一个空字符。换行符被丢弃,输入队列中的下一个字符是下一行中的第一个字符。这里不需要进行任何转换。
对于输出,将执行相反的转换。即整数被转换为数字字符序列,浮点数被转换为数字字符和其他字符
组成的字符序列非(如284.53
或-1.58E+06
)。字符数据不需要做任何转换。
这里的要点是,输入一开始为文本。因此,控制台输入的文件版本是文本文件,即每个字节都存储了
一个字符编码的文件。
写入到文本文件
对于文件输出,C++ 使用类似cout
的东西。
- 必须包含头文件
fstream
; - 头文件
fstream
定义了一个用于处理输出的ofstream
类; - 需要声明一个或多个
ofstream
变量(对象),并命名; - 必须指明名称空间
std
; - 需将
ofstream
对象与文件关联起来,方法之一是使用open()
方法(新建一个文件); - 使用完文件,要使用
close()
方法将其关闭; - 可结合使用
ofstream
对象和运算符<<
来输出各种类型的数据。
注意:头文件iostream
提供了一个预先定义好的名为cout
的ostream
对象,但必须自己声明自己的ofstream
对象,为其命名,并将共与文件关联起来。
注意:方法open()
接受一个C-风格字符串作为变量,这可以是一个字面字符串,也可以是存储在数组中的字符串。
重要的是,声明一个ofstream
对象并将其同文件关联起来后,便可以像使用cout
那样使用它。所有可用于cout
的操作和方法(如<<
、endl
和setf()
)都可用于ofstream
对象。
总之,使用文件输出的主要步骤如下:
- 包含头文件
fstream
; - 创建
ofstream
对象; - 将
ofstream
对象与一个文件关联; - 像使用
cout
那样使用ofstream
对象。
读取文件文件
读取文件与控制台输入类似。
- 必须包含头文件
fstream
; - 头文件
fstream
定义了一个用于处理输入的ifstream
类; - 需要声明一个或多个
ifstream
变量(对象),并命名; - 必须指明名称空间
std
; - 需将
ofstream
对象与文件关联起来,方法之一是使用open()
方法; - 使用完文件,要使用
close()
方法将其关闭; - 可结合使用
ifstream
对象和运算符>>
来读取各种类型的数据。 - 可结合使用
ifstream
对象和get()
方法来读取一个字符,getline()
方法来读取一行字符。 - 可结合使用
ifstream
对象和eof()
和fail()
等方法判断输入是否成功。
注意:头文件iostream
提供了一个预先定义好的名为cin
的istream
对象,但必须自己声明自己的ifstream
对象,为其命名,并将共与文件关联起来。
重要的是,声明一个ifstream
对象并将其同文件关联起来后,便可以像使用cin
那样使用它。所有可用于cin
的操作和方法都可用于ifstream
对象。
检查文件是否被成功打开的首先方法是使用方法is_open()
,如果文件被成功打开,方法is_open()
将返回true
。
函数exit(EXIT_FAILURE)
的原型和同操作系统通信的参数在头文件cstdlib
中定义。
方法is_open()
是 C++ 中相对较新的内容,如果编译器不支持,可使用较老的方法good()
来代替,该方法在没有任何错误的时候返回true
。
第 6 章总结
C++ 提供了if
语句、if else
语句和switch
语句来管理选项。if
语句使程序有条件地执行语句或语句块,也就是说,如果满足特定的条件,程序将执行特定的语句或语句块。if else
语句程序选择执行两个语句或语句块之一。可以在这条语句后再加上if else
,以提供一系列的选项。switch
语句引导程序执行一系列选项之一。
C++ 还提供了帮助决策的运算符。if
和if else
语句通常使用关系表达式作为测试条件。通过使用逻辑运算符(&&
、||
和!
),可以组合或修改关系表达式,创建更细致的测试。条件运算符(?:
)提供了一种选择两个值之一的简洁方式。
cctype
字符函数库提供了一组方便的、功能强大的工具,可用于分析字符输入。
对于文件 I/O 来说,循环和选择语句是很有用的工具;文件 I/O 与控制台 I/O 极其相似。声明ifstream
和ofstream
对象,并将它们同文件关联起来后,便可以像使用cin
和cout
那样使用这些对象。
使用循环和决策语句,便可以编写有趣的、智能的、功能强大的程序。