《C++ Primer plus 》第六章:分支语句和逻辑运算符

if语句

  1. if (test-condition)
    statement

  2. if
    else

  3. if
    else if
    else

逻辑表达式

  1. 逻辑OR运算符:||

    C++规定,||运算符是个顺序点(sequence point)。也是说,先修改左侧的值,再对右侧的值进行判定。例如,如下表达式
    i++ < 6 || i == j
    假设 i 原来的值为10,在将i++与6进行比较时,i++的值为10,但在将i与j进行比较时,i的值为11;

    另外,如果左侧的表达式为true,则C++将不会去判定右侧的表达式,因为只要一个表达式为 true,则整个逻辑表达式为 true(冒号和逗号运算符也是顺序点)

  2. 逻辑AND运算符:&&

  3. 逻辑NOT运算符:!

    一些细节:

    C++逻辑OR和逻辑AND运算符的优先级都低于关系运算符。
    这意味着下面的表达式:
    x > 5 && x < 10
    将被解释为:
    (x>5) && (x<10)
    另一方面,!运算符的优先级高于所有的关系运算符和算术运算符。因此,要对表达式求反,必须用括号将其括起,如下所示:
    !(x>5)
    而!x > 5 的值总是false,因为!x的值只能为true或false,而它们将被转换为 1 或 0.

    逻辑 AND 运算符的优先级高于逻辑 OR 运算符。因此,表达式:

    age > 30 && age < 45 || weight > 300
    会被解释为 :(age > 30 && age < 45) || (weight > 300)
    如果这两个条件中的一个或全部都为 true,则整个表达式为true。

    但最简单的方法就是用括号,这样代码容易阅读,避免读者查看不常使用的优先级规则,并减少由于没有准确记住所使用的规则而出错的可能性。

    C++提供了逻辑运算符的另一种表示方式:
    && ----- and
    || ------ or
    ! ----- not
    这意味着 and、or、not 都是C++保留字,不能用作变量名。它们并不是C语言的保留字,但是在程序中包含了iso646.h头文件,C程序也可以将它们用作运算符。

字符函数库 cctype

C++从C语言继承了一个与字符相关的、非常方便的函数软件包,它可以简化诸如确定字符是否为大写字母、数字、标点符号等工作,这些函数的原型是在头文件cctype(老式风格为ctype.h)中定义的。例如,如果ch是一个字母,则 isalpha(ch) 函数返回一个非零值,否则返回0。同样,如果 ch 是标点符号(如逗号或句号),函数 ispunct(ch) 将返回 true。(这些函数的返回类型为 int,而不是 bool,但通常 bool 转换 可以让程序员把它们当作 bool 类型。)

函数名称返回值
isalnum()如果参数是字母数字,即字母或数字,该函数返回true
isalpha()如果参数是字母,该函数返回 true
iscntrl()如果参数是控制字符,该函数返回 true
isdigit()如果参数是数字(0~9),返回 true
isgraph()如果参数是除空格之外的打印字符,返回true
islower()如果参数是小写字母,返回true
isprint()如果参数是打印字符(包括空格),返回true
ispunct()如果参数是标点符号,返回 true
isspace()如果参数是标准空白字符,如空格、进纸、换行符、回车、水平制表符或者垂直制表符,返回true
isupper()如果参数是大写字母,返回 true
isxdigit()如果参数是十六进制数字,即 0~ 9、a~ f或 A ~ F,返回 true
tolower()如果参数是大写字符,则返回其小写,否则返回该参数
toupper()如果参数是小写字符,则返回其大写,否则返回该参数

条件运算符 ?:

C++有一个常被用来代替 if else 语句的运算符,这个运算符被称为条件运算符(?:),条件运算符(?:)是 C++ 中唯一一个需要 3 个操作数的运算符。该运算符的通用格式如下:
expression1 ? expression2 : expression3
如果 expression1 为 true,则整个表达式的值为 expression2 的值;否则,整个表达式的值为 expression3 的值。下面的两个示例演示了该运算符是如何工作的:

5 > 3 ? 10 : 12  		// 5>3 is true, so expression value is 10
3 ==  9 ? 25 : 18     	// 3 == 9 is false, so expression value is 18

用一句话概括就是:真前假后

switch 语句

switch (integer-expression){
	case label1 : statement(s)
	case label2 : statement(s)
	case label3 : statement(s)
	...
	default		: statement(s)
}

顾名思义,interger-expression 必须是一个结果为整数值的表达式相应的,每个标签都必须是整数常量表达式

最常见的标签是 int 或 char 常量,也可以是枚举量。
如果 integer-expression 不与任何标签匹配,则程序将跳到标签为 default 的那一行。
Default 标签是可选的,如果被省略,而又没有匹配的标签,则程序将跳到 switch 后面的语句处执行。

C++ 中的 case 标签只是行标签,而不是选项之间的界限。也就是说,程序跳到switch中特定代码行之后,将依次执行之后的所有语句,除非有明确的其它指示。程序不会在执行到下一个case处自动停止,要让程序执行完一组特定语句后停止,必须使用 break 语句,这将导致程序跳到 switch 后面的语句处执行。switch语句会执行第一次进入case之后的所有语句,包括在那之后的其它case的语句

char choice;
cin >> choice;
while (choice != 'Q' && choice != 'q'){
	switch(choice){
		case 'a':
		case 'A': cout << "\a\n";
					break;
		case 'r':
		case 'R': report();
					break;
		case 'c':
		case 'C': comfort();
					break;
		default : cout << "That's not a choice.\n"
	}
	showmenu();
	cin >> choice;
}

由于case ‘a’ 后面没有 break 语句,因此程序将接着执行下一行——case ‘A’ 后面的语句。

switch 语句 和 if else 语句都允许程序从选项中进行选择。相比之下,if else 更通用。例如,它可以处理取值范围,如下所示:

if (age > 17 && age < 35)
	index = 0;
else if (age >=35 && age < 50)
	index = 1;
else if (age >=50 && age < 65)
	index = 2;
else
	index = 3;

然而,switch并不是为处理取值范围而设计的。switch语句中的每一个case标签都必须是一个单独的值。另外,这个值必须是整数(包括 char),因此 switch 无法处理浮点测试。另外 case 标签值还必须是常量。如果选项设计取值范围、浮点测试或两个变量的比较,则应使用 if else 语句。

然而,如果所有的选项都可以使用整数常量来标识,则可以使用 switch 语句 或 if else 语句。由于switch语句是专门为这种情况设计的,因此,如果选项超过了两个,则就代码长度和执行速度而言,switch语句的效率更高。

break 和 continue 语句

break 和 continue 语句都使程序能够跳过部分代码。可以在 switch 语句或任何循环中使用 break 语句,使程序跳到 switch 或循环后面的语句处执行。continue 语句用于循环中,让程序跳过循环体中余下的代码,并开始新一轮循环。

虽然 continue 语句会跳过循环体的剩余部分,但不会跳过循环的更新表达式。在for循环中,continue 语句使程序直接跳到更新表达式处,然后跳到测试表达式处。
然而,对于while循环来说,continue 将使程序直接跳到测试表达式处,这意味着位于continue之后的更新表达式都将被跳过。在某些情况下,这可能是一个问题。

和 C 语言一样, C++ 也有goto语句。下面的语句将跳到使用 paris: 作为标签的位置:
goto paris;
也就是说,可以有下面这样的代码:

char ch;
cin >> ch;
if(ch == 'P')
	goto paris;
cout << ...
...
paris: cout << "You've just arrived at Paris.\n";

在大多数情况下(有些人认为,在任何情况下),使用 goto 语句不好,而应使用结构化控制语句(如 if else、switch、continue 等)来控制程序的流程。

读取数字的循环

int n;
cin >> n
如果用户输入一个单词,而不是一个数字,情况将如何呢?发生这种类型不匹配的情况时,将发生4种情况:

  • n的值保持不变
  • 不匹配的输入将被留在输入队列中
  • cin对象中的一个错误标记被设置
  • 对cin方法的调用将返回false(如果被转换为bool类型)
    方法返回false意味着可以用非数字输入来结束读取数字的循环。非数字输入设置错误标记意味着必须重置该标记,程序才能继续读取输入。clear()方法重置错误输入标记,同时也重置文件尾。输入错误和EOF都将导致cin返回false。
int golf[Max];
cout << "Please enter your golf scores.\n";
cout << "You must enter " << Max << " rounds.\n";
int i;
for (i=0; i < Max; i++){
	cout << "round #" << i+1 << ": ";
	while(!(cin>>golf[i])){
		cin.clear()
		while (cin.get() != '\n')
			continue;
		cout << "Please enter a number: ";
	}
}

简单的文件输入/输出

C++使得将读取键盘输入和在屏幕上显示输出(统称为控制台输入/输出、控制台I/O)的技巧用于文件输入/输出(文件I/O)非常简单。

这里讨论文本文件,即每个字节都存储了一个字符编码的文件。

先总结一下有关将cout用于控制台输出的基本事实,为文件输出做准备:

  • 必须包含头文件 iostream
  • 头文件iostream定义了一个用来处理输出的 ostream 类
  • 头文件iostream声明了一个名为cout的ostream变量(对象)
  • 必须指明名称空间std;例如,为引用元素cout和endl,必须使用编译指令using或者前缀std::。
  • 可以结合使用cout和运算符<<来显示各种类型的数据

文件输出与此极其相似

  • 必须包含头文件 fstream
  • 头文件 fstream定义了一个用于处理输出的 ofstream 类
  • 需要声明一个或多个ofstream变量(对象),并以自己喜欢的方式命名,但要遵守命名规则
  • 必须指明名称空间std;例如,为引用元素 ofstream,必须使用编译指令 using 或前缀 std::
  • 需要将 ofstream 对象与文件关联起来。为此,方法之一是使用 open() 方法
  • 使用完文件后,应使用方法 close() 将其关闭
  • 可结合使用 ofstream 对象和运算符<<来输出各种类型的数据

注意,虽然头文件iostream提供了一个预先定义好的名为cout的ostream对象,但您必须声明自己的ofstream对象,为其命名,并将其同文件关联起来。

下面演示了如何声明这种对象:
ofstream outFile;
ofstream fout;

下面演示了如何将这种对象与特定的文件关联起来:
outFile.open(“fish.txt”);
char filename[50];
cin >> filename;
fout.open(filename)
方法open()接受一个C-风格字符串作为参数,这可以是一个字面字符串,也可以是存储在数组中的字符串。
下面演示了如何使用这种对象:
double wt = 125.8;
outFile << wt;
char line[81] = “Objects are closer than they appear.”;
fout << line << endl; // write a line of text

重要的是,声明一个 ofstream 对象并将其同文件关联起来后,便可以像使用 cout 那样使用它。所有可用于 cout 的操作和方法(如 <<、endl 和 setf())都可用于 ofstream 对象(如前述示例中的 outFile 和 fout)。

总之,使用文件输出的主要步骤如下:

  1. 包含头文件 fstream
  2. 创建一个 ofstream 对象
  3. 将该 ofstream 对象同一个文件关联起来
  4. 就像使用 cout 那样使用该 ofstream 对象

默认情况下,open()将首先截断该文件,即将其长度截短到零——丢其原有的内容,然后将新的输出加入到该文件中。
打开文件用于接受输入时可能失败。例如,指定的文件可能已经存在,但是禁止对其进行访问。因此细心的程序员将检查打开文件的操作是否成功,这将在下一个例子中介绍。

接下来介绍文本文件输入,它是基于控制台输入的。控制台输入涉及多个方面,下面首先总结这些方面:

  • 必须包含头文件iostream
  • 头文件 iostream 定义了一个用处理输入的 istream 类
  • 头文件 iostream 声明了一个名为 cin 的 istream 变量(对象)
  • 必须指明名称空间 std; 例如,为引用元素 cin,必须使用编译指令 using 或前缀 std::
  • 可以结合使用 cin 和运算符 >> 来读取各种类型的数据。
  • 可以使用cin和get()方法来读取一个字符,使用cin和getline()来读取一行字符
  • 可以结合使用cin和eof()、fail()方法来判断输入是否成功。
  • 对象 cin 本身被用作测试条件时,如果最后一个读取操作成功,它将被转换为布尔值 true,否则被转换为 false

文件输入于此极其相似:

  • 必须包含头文件 fstream
  • 头文件 fstream 定义了一个用于处理输入的 ifstream 类
  • 需要声明一个或多个 ifstream 变量(对象),并以自己喜欢的方式对其进行命名,条件是遵守常用的命名规则
  • 必须指明名称空间 std;例如,为引用元素 ifstream,必须使用编译指令 using 或前缀 std::
  • 需要将 ifstream 对象和运算符 >> 来读取各种类型的数据
  • 可以使用ifstream对象和get()方法来读取一个字符,使用 ifstream 对象和getline() 来读取一行字符
  • 可以结合使用 ifstream 和 eof()、fail()等方法来判断输入是否成功
  • ifstream对象本身被用作测试条件时,如果最后一个读取操作成功,它将被转换为布尔值true,否则被转换为false

如果试图打开一个不存在的文件用于输入,情况将如何呢?这种错误将导致后面使用 ifstream 对象进行输入时失败。检查文件是否被成功打开的首先方法是使用方法 is_open(),为此,可以使用类似于下面的代码:

inFile.open("bowling.txt");
if ( !inFile.is_open()){
	exit(EXIT_FAILURE);
}

inFile >> value;
while(inFile.good()){
	...
}
if(inFile.eof()){
}
else if (inFile.fail()){
}
else{

}
inFile.close();

注意,good()方法指出最后一次读取输入的操作是否成功,这一点至关重要。为此,一种标准的方法是,在循环之前(首次执行循环测试之前)放置一条输入语句,并在循环的末尾(下次执行循环测试之前)放置另一条输入语句:

inFile >> value;
while(inFile.good()){
	...
	inFile >> value;
}

或者,直接改为
while(inFile >> value){

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值