第四章:分支结构
4.1 逻辑表达式
4.1.1 关系运算符:
==(判断是否相等),!=(判断是否不等),> ,<,>=(判断是否大于或等于),<=(判断是否小于或等于)。(左结合,均为二元运算符)
由于C语言中没有布尔值,关系运算符返回的结果为整型0和1。C语言遵循非0即真的原则:0表示假,非0表示真。
注意:判断是否相等的时候不要直接用==或者!=
原因有:
- 浮点数表示的限制:
如果两个数在浮点数表示范围内非常接近,并且它们之间的差异小于浮点数精度的最小单位(即机器的epsilon),那么计算机可能将它们视为相同的数。这是因为浮点数只能表示有限的精度,所以两个非常接近的数可能在浮点表示中具有相同的值。
eg:
#include <stdio.h>
int main()
{
if(1.499999999999999999999999999999999999999999999999999999999999999999999==1.50000000000000000000000000000000000000000000000000000)
printf("Yes");
else
printf("No");
return 0;
}
结果:
- 舍入误差的累积:
在进行一系列的浮点运算后,舍入误差可能会累积,导致原本相差较大的数经过一系列计算后变得非常接近,以至于它们在浮点表示中看起来相同。 - 编程错误:
另一种可能是代码逻辑中的错误,例如错误地使用了整数除法、类型转换问题或者逻辑判断错误等,导致本应不同的数被误判为相等。 - 显示精度不足:
在某些情况下,输出或显示的精度不足也会给人造成误解。例如,两个不同的浮点数在屏幕上以较少的小数位显示时看起来可能相同,但实际上它们并不相同。
因此为了解决这个问题,我们在判断两个数是否相等的时候需要引入一个精度值,然后判断fabs(a-b)或者abs(a-b)是否小于给定的精度要求。
4.1.2 逻辑运算:
C语言的“ 与 ”:&&; “ 或 ”:||; “ 非 ”:!。
逻辑与(&&),逻辑或(||)是二元运算符;逻辑非(!)是一元运算符。都是左结合。通常情况下以0表示false、1表示true,为了应对逻辑运算时操作数是0和1以外的其它值,对“通常情况”进行了扩展:任何基本类型(char、int、double等等)及指针类型的数据都可以当作逻辑型数据,当其二进制形式的所有位全为0时,该值表示false,否则表示true,“非0即真”。但是,逻辑运算的结果仍然以整数0和1表示
逻辑与(&&):两者都为真,结果就为真,否则为假
逻辑或(||):两者只要有一个为真,结果就为真,否则为假
逻辑非(!):对逻辑值取反。逻辑值为真,结果为假;逻辑值为假,结果为真。
逻辑运算符 && 和 || 具有短路行为。这意味着在 a && b 中,如果 a 为假,则不会评估 b;在 a || b 中,如果 a 为真,则不会评估 b。
x | y | x&&y | x||y | !x | !y |
---|---|---|---|---|---|
1(非0) | 1(非0) | 1 | 1 | 0 | 0 |
1(非0) | 0 | 0 | 1 | 0 | 1 |
0 | 1(非0) | 0 | 1 | 1 | 0 |
0 | 0 | 0 | 0 | 1 | 1 |
分支结构也称为选择语句,是三种基本程序结构之一。分支结构是指在程序中编写了两组或多组操作语序命令,要求计算机根据执行程序时的情况选择其中的一组执行。
4.2 if 语句
4.2.1 执行 if 语句的流程:
基本格式:
if (逻辑表达式)
操作A;
else
操作B;
“操作A”被称为“if 分支”,“操作B”被称为“else 分支”。这条语句的意思是:先计算逻辑表达式的值。如果计算结果是逻辑“真”(非0),则执行“操作A”且不执行“操作B”;反之,如果逻辑表达式的计算结果为 0 ,则执行“操作B”而不执行“操作A”。if 语句命令计算机作排他性的二选一处理。注意:不要在 “ if (逻辑表达式)”后面加分号,也不能在 else 后面再加 “(条件)”
4.2.2 在 if 语句的分支中使用复合语句
在某些情况下,一条语句不足以处理某一路分支中的操作,这时就需要使用复合语句。复合语句是在一组语句序列的前后加上一对{ }构成的。从理解的角度看,可以认为复合语句是程序中的一个功能块,是“告诉”计算机把{ }及其中的内容当作一个整体,{ }中的语句序列是实现这个功能的具体步骤。在C语言的语法规则中,任何要求写一条语句的地方都可以写复合语句。
4.2.3没有else 分支的 if 语句
“无操作”也就是“空操作”。
格式:
if(逻辑表达式)
操作A;
else
;//空语句
//也可以简化成没有else分支的格式
if(逻辑表达式)
操作A;
4.2.4 if 语句的嵌套
如果if 语句的分支功能呢=比较复杂,需要再用分支结构实现,则构成在 if 语句分支中在使用 if 语句,即 if 语句的嵌套。
4.3 条件表达式
格式:
三元运算符。意思是:先计算逻辑表达式的结果,如果计算结果为逻辑真则处理表达式A,并且以表达式A的计算结果作为整个条件表达式的值,否则处理表达式B,并且以表达式B的计算结果作为整个条件表达式的值。
如果把条件表达式当作一条语句使用,则在效果上等效于:
if (逻辑表达式)
操作A;
else
操作B;
4.4 多路分支
- 用 嵌套的 if 语句:
if(逻辑表达式1)
操作1;
else if(逻辑表达式2)
操作2;
······
else if(逻辑表达式n)
操作n;
- 用switch语句
格式:
switch(表达式)
{
case 常量1:操作1;
case 常量2:操作2;
······
case 常量n:操作n;
default:操作n+1;
}
执行该语句时,先计算出表达式的值,然后依次跟常量1、常量2、…比较,一旦发现跟常量i相等,则从操作i开始执行,依次做操作i+1、操作i+2、…直至操作n+1(操作n+1也要执行)。switch语句排列了一组操作,根据“表达式”的计算结果决定从这一组操作中的哪一项开始执行。
语法规则:
- 执行时将做“表达式==常量i”的比较,两者必须是可比较的;
- case后面必须是常量(整数或者char),不得是变量,也不得是类似x>0之类的条件;
- 表达式的类型必须是整数或者char,不得是float和double;
- 如果“操作n+1”是空操作,则可以不写default那一行;
- 执行时将做“表达式==常量i”的比较,若全不匹配,则执行default的“操作n+1”。
嵌套switch语句:
把一个 switch 作为一个外部 switch 的语句序列的一部分,即可以在一个 switch 语句内使用另一个 switch 语句。即使内部和外部 switch 的 case 常量包含共同的值,也没有矛盾。
switch(ch1) {
case 'A':
printf("这个 A 是外部 switch 的一部分" );
switch(ch2) {
case 'A':
printf("这个 A 是内部 switch 的一部分" );
break;
case 'B': /* 内部 B case 代码 */
}
break;
case 'B': /* 外部 B case 代码 */
}
实现switch语句的排他性的多路分支:
排他性多路分支是指在n项操作中选做一项而其它项不执行,用switch语句实现这样的效果通常写作:
switch(表达式)
{
case 常量1:操作1;break;
case 常量2:操作2;break;
… …
case 常量n:操作n;break;
default:操作n+1;
}
用switch语句实现排他性多路分支时,如果两个常量后面的操作是一样的,则可以写成:
switch(表达式)
{
case 常量1:操作1;break;
… …
case 常量i: //此处空着
case 常量i+1:操作i+1;break;
… …
case 情况n:操作n;break;
default:操作n+1;
}
当发现表达式的值与常量i相等时,本应选做操作i,但此时操作i没有内容,也没有break,因此顺序向下执行,从而会继续执行操作i+1。