if…else语句通过对一个条件进行判断,当条件为真时,执行一个操作,否则执行另一个不同的操作。if…else语句的语法格式如下:
对应的流程图如图3-1所示,如果表达式的值为真,则执行语句1,否则执行语句2。其中,语句1和语句2可以是一条单独的语句,也可以是用花括号括起来的一组语句。
图3-1 双分支if语句流程图
if(表达式)、语句1、else和语句2一起组成了一个分支结构,它们并非两条完整的语句,if条件表达式的括号后面没有分号。
请注意语句1和语句2中都有一个缩进。这样的缩进并不是语法上的要求,是可选的。但是强烈推荐采用这样的缩进,因为它有利于突出结构化程序的内在结构特点,使程序易于理解。本书采用“缩进”这样的程序书写风格。缩进增加的空格并不会使编译后得到的目标程序变大,因为编译器在编译时会将所有的空白符,如空格、Tab键和换行符全部忽略。
解决问题:输出两个整数中较大的一个。
从键盘输入两个整数,要求输出这两个整数中较大的一个。
解题思路: 如果a > b,则输出a的值,否则输出b的值。用如下伪代码来表达该问题的求解过程。
(1)读入整数a、b;
(2)如果a > b,则输出a的值;
否则,输出b的值。
/*程序3-1:使用if…else语句输出两个数的最大值*/
(1)将if控制的语句体中的语句整体向后缩进,是一个很好的编程习惯,有利于突出代码段的内在结构特点;
(2)if()后面没有分号!如果不小心在后面加了分号,会有语法错误,错误提示会指向else:非法的else,没有与之匹配的if;
(3)建议用花括号明确表示if或else的控制范围。
在编写程序3-1之前,先使用了伪代码分析问题:
(1)读入整数a、b;
(2)如果a > b,则输出a的值;
否则,输出b的值。
伪代码是一种人工的、非正式的辅助人们来进行算法设计的语言。伪代码跟我们日常使用的语言极为类似,但它能方便地转换为C语言程序,并且书写方便、易学易用。
伪代码程序只包含“操作语句”,变量定义语句不是“操作语句”,例如:
int i;
只是程序员想通知编译器:名为i的变量的类型是int,为其预留出相应的存储空间。所以在编写伪代码程序时,可以不进行变量定义。但是有的程序员喜欢在伪代码程序的开头列出所有的变量,并简要说明其目的。
使用伪代码有助于程序员在编写程序前专心地“思考”程序该如何设计,至于将伪代码转换成C语言源程序的工作就是相对简单的劳动了。
解决问题考是否通过
从键盘读入一个整数,代表一个学生的考试成绩,若大于或等于60分,则输出“Passed”,否则输出“Failed”。
解题思路: 因为问题比较简单,可直接用如下伪代码来表达该问题的求解过程。
(1)读入成绩score;
(2)如果score >=60,则输出“Passed”;
否则,输出“Failed”。
/*程序3-2:使用if…else语句判别考试是否通过*/
在if控制语句中,else子句是可选项。缺省else子句的if语句格式如下:
如果括号内表达式的值为真,则执行if后面的语句,否则什么也不做。语句是否执行取决于表达式的值。下面这条if语句是通过比较成绩是否小于60,来决定是否执行输出语句:
if(score < 60)
printf(″不及格\n″);
解决问题:输出两个整数中较大的一个。
从键盘读入两个整数,要求输出这两个整数中较大的一个。
解题思路: 用变量max来存储最大值,先将a赋给max,然后判断b是否大于max,如果是,则将b赋给max。用如下伪代码来表达该问题的求解过程。
(1)读入整数a、b;
(2)将a存入max(暂时认为a最大);
(3)如果b>max,用b更新max;
(4)输出max。
/*程序3-3:使用基本if语句求两个整数的最大值*/
也许初学者会认为程序3-3不如程序3-1直接输出结果那么简洁明了,但这种方法很有启发性,易于扩充到规模更大的问题上,例如求3个整数的最大值,详见程序3-4。
关系运算符用于比较表达式,提出“b是否大于max”等问题。含有关系运算符的表达式的运算结果只有两个:1(true)或0(false)。因此,关系运算的结果是整型数据。如果关系成立,结果为1;如果关系不成立,结果为0。
关系运算符用于比较整数和浮点数,也允许比较混合类型的操作数。常用的关系运算符如表3-1所示。
表3-1 关系运算符
关系运算符的优先级低于算术运算符,其中,前四个运算符的级别比后两个的优先级高。
表达式1 < 2==3 < 4的结果为1,因为该表达式等价于(1 < 2)==(3 < 4)。
表达式4==4 > 0的结果为0,因为“>”运算符优先级高于“==”,故表达式等价于4==(4 > 0),而子表达式(4 > 0)的值为1,进而表达式4==1的值为0。
表达式4 > 3 > 2的结果为0,因为该表达式等价于(4 > 3)> 2,而子表达式(4 > 3)的值为1,进而表达式1 > 2的值为0。初学者很容易受数学习惯的影响,把表达式4 > 3 > 2理解为4 > 3并且3 > 2,这需要引起注意,在C语言中,表达式4 > 3 > 2是按优先顺序计算的,没有并且的含义。在C语言中如何表示数学表达式“a < x < b”将在3.2一节讲解。
解决问题:求三个整数的最大值。
从键盘上读入三个整数,要求输出这三个整数中最大的数。
解题思路:
方法1: 如果用程序3-1中直接输出结果的方法,需要列举出所有可能的关系:
如果a >=b并且a >=c,则输出a
否则,如果b >=a并且b >=c,则输出b
否则,如果c >=a并且c >=b,则输出c
方法2: 如果用程序3-3的方法,则可在程序3-3的基础上进行扩充。在程序3-3中,已将a和b的最大值存入max,在此基础上,让c与max比较:如果c > max,则用c更新max。
实现过程如下:
(1)读入整数a和b;
(2)将a存入max(暂时认为a最大);
(3)如果b > max,用b更新max;
(4)如果c > max,用c更新max;
(5)输出max。
/*程序3-4:使用if语句求三个整数的最大值*/
(1)第一个常见的错误是:if语句中,在括起条件的右括号后面多写了一个分号;
(2)第二个常见错误是:将“==”和“=”弄混淆了;
(3)将if控制的语句体中的语句整体向后缩进,是一个很好的编程习惯;
(4)为了增加程序的可读性,最好在每个if语句的前后都留出一个空行。
在if语句中,if子句或else子句条件能控制的只是一条语句,而实际情况中条件分支要处理的操作往往需要多条语句才能完成,这时就要使用花括号将这些语句括起来。一般地,将一组逻辑相关的语句用一对花括号{}括起来所构成的语句,称为复合语句,也叫语句块,其一般形式为:
由于复合语句在逻辑上形成一个整体,因此可以被当作一条语句来处理,并且可以用在单个语句可以使用的任何地方。
解决问题:交换两个变量的值。
输入两个整数存入a、b两个变量,若a>b,则a与b交换内容,即:要求a中存较小数,b中存较大数,最后输出a和b的值。
解题思路:
(1)从键盘读入两个整数存入a、b两个变量中;
(2)如果a > b,则互换a和b的内容。
此问题的难点在于如何互换两个变量的内容。内存的特性是对其赋值后,原有的内容会被覆盖,所以不能简单地用"a=b;b=a;"这两条赋值语句来实现互换。
其道理等同于这样一个问题:有一瓶雪碧(用a表示)和一瓶可乐(用b表示),现在,要求用雪碧瓶子装可乐,可乐瓶子装雪碧,如何实现?
相信大家都有答案:找一个空瓶子(用t表示)来周转,如图3-2所示。
图3-2 两个瓶子交换内容
交换两瓶饮料的具体步骤如下:
(1)把a瓶中的雪碧倒入空瓶t中;
(2)把b瓶中的可乐倒入a瓶中;
(3)把暂存在t瓶中的雪碧倒入b瓶中。
交换两个变量值的步骤如下:
(1)把a的值存入t中:t=a;
(2)把b的值存入a中:a=b;
(3)把t的值存入b中:b=t;
由此可知,此问题对应的源代码如下:
/*程序3-5:使用复合语句交换两个变量的值*/
运行结果:
此例中,要注意if语句控制的范围,如果if后面的条件成立,要执行的语句多于一条,一定要用花括号括成一条复合语句。如果上面的if语句改为:
运行结果:
输入:3 5↙
输出:5 -858993460
为什么出现这样的结果?通过单步执行会发现,只有“t=a;”这条语句受if的限制,而“a=b;b=t;”这两条语句不再受if的限制,当if后面的条件不成立时也会被执行,因此会把b的值赋给a,把t的值赋给b,而t没有初始化,所以b被赋为一个垃圾值。
除了if语句,C语言还提供了一种特殊的运算符,用来依据条件选择两个值中的一个。条件表达式的格式:
表达式1 ?表达式2:表达式3
以上的组合表达式称为条件表达式,它是唯一一个要求三个操作数的运算符,因此,常将其称为三元运算符。
求解过程:
(1)求解表达式1的值;
(2)如果表达式1的运算结果为1(非0),求解表达式2的值,将其作为整个表达式的值,表达式3不计算;
(3)如果表达式1的运算结果为0,求解表达式3的值,将其作为整个表达式的值,表达式2不计算。
/*程序3-6:使用条件表达式求两个整数的最大值*/
其中(a > b)? a:b是一个条件表达式,若条件(a>b)成立,则条件表达式取值a;否则,取值b。由此可以将程序3-4改写成程序3-7。
/*程序3-7:用条件表达式求三个整数的最大值*/
到目前为止,所接触到的都是用关系运算符表达的简单条件,当作出决策需要测试多个条件时,只能采用if…else的嵌套或其他多分支结构。事实上,C语言提供了用于将简单条件连接在一起构成复杂条件的逻辑运算符,主要有:&&(逻辑与运算)、||(逻辑或运算)、!(逻辑非运算)。用逻辑运算符连接操作数组成的表达式称为逻辑表达式。
逻辑与运算的特点是:仅当两个操作数都为真时结果才为真,其他情况都为假。当需要两个条件同时为真时,使用逻辑与运算符“&&”把两个条件连接起来。例如,判断一个整型变量a是否位于[0,100],所对应的表达式为:0<=a && a <=100,或者a>=0 && a<=100。注意,千万不能写成0<=a<=100。
逻辑或运算的特点是:仅当两个操作数都为假时结果才为假,其他情况都为真。因此,当需要表示两个条件只要有一个成立时,可使用逻辑或来连接这两个条件。例如,判断某人的年龄属于60以上或12以下的范围,所对应的表达式为:age > 60 || age < 12。
逻辑非运算符“!”用于反转一个条件的值。逻辑非运算符只需要一个操作数,若操作数为真,则该逻辑表达式为假;若操作数为假,则该逻辑表达式为真。当需要某个条件为假时,则要在这个条件前面加上逻辑非运算符“!”。
逻辑表达式的值,即逻辑运算的结果只有真和假两个值,C语言没有提供布尔类型,当运算结果为真时用1表示,为假时用0表示。但是在需要判断一个数值表达式(不一定是逻辑表达式)真假的时候,由于任意一个数值表达式的值不只局限于0和1两种情况,因此根据表达式的值为非0还是0来判断其真假。如果表达式的值为非0则为真,否则为假。逻辑运算符的运算规则如表3-2所示。
表3-2 逻辑运算符运算规则表
3个逻辑运算符的优先级各不相同,其中,逻辑非运算符!的优先级高于关系运算符和所有的双目运算符;而运算符&&和||的优先级则低得多,低于所有算术运算符和关系运算符;而运算符&&的优先级又高于运算符||。C语言提供的逻辑运算符优先级和结合性如表3-3所示。
表3-3 逻辑运算符的优先级和结合性
合理地运用C语言的算术运算符、关系运算符和逻辑运算符,可以巧妙地用一个C语言表达式来表示实际应用中的一个复杂的条件,下面举例说明。
条件1:“变量a、b不同时为0”,可表示为如下逻辑表达式:
a !=0 || b !=0
或
!(a==0 && b==0)
条件2:“变量a、b至少有一个为0”,可表示为如下逻辑表达式:
a==0 || b==0
条件3:“变量a、b异号”,这个条件在数学中经常转换为a * b < 0,但在C程序中,这么处理是有问题的,因为如果a和b是int类型,虽然a和b都在int范围内,但a * b可能会超出int范围。更可行的方法是变乘法为除法(在确定b不为0的前提下):
a / b < 0
或者使用逻辑表达式:
a > 0 && b < 0 || a < 0 && b > 0
要想正确计算一个复杂表达式的值,需要先了解一些常用运算符的优先级和结合性(见表3-4)。
表3-4 常见运算符的优先级
当然,记不住这些优先级也不必惊慌,“将需要先计算的表达式用圆括号括起来”是解决这个问题的灵丹妙药。在表达式
a > 0 && b < 0 || a < 0 && b > 0
中加上一些并不必须的括号,是一个很好的习惯。
(a > 0 && b < 0)|| (a < 0 && b > 0)
闰年是为了弥补因人为历法规定造成的年度天数与地球实际公转周期的时间差而设立的。地球绕太阳运行周期为365.242 19天,即一回归年。公历的平年只有365日,比回归年短约0.242 2日,每四年累积约一天,把这一天加于2月末(2月29日),这一年就为闰年。按照每四年一个闰年计算,平均每年就要多算出0.007 8天,经过四百年就会多出大约三天来,因此,每四百年中要减少三个闰年。所以规定公历年份是整百数的,必须是400的倍数才是闰年,不是400的倍数就是平年。
解决问题:判断闰年。
编写程序,对于用户输入的某个年份,判断是否是闰年,若是闰年输出“yes”,否则输出“no”。
解题思路:
年份year是闰年须满足下列两个条件之一:
(1)能被4整除,但不能被100整除;
(2)能被400整除。
解决方案1:使用嵌套的if语句。
将一个if语句放在另一个if语句中,形成嵌套的if语句,可用于测试更多的条件。
首先把年份分为是4的倍数和不是4的倍数两类:
若year不是4的倍数,则不是闰年;
否则,还要继续分为是100的倍数和不是100的倍数:
若year不是100的倍数,则是闰年;
否则,还要继续分为是400的倍数和不是400的倍数:
若year是400的倍数,则是闰年;
否则,不是闰年。
嵌套的if语句如下:
在嵌套的if语句中可能出现多个if和else,此时就要注意if和else的配对问题。例如:
这个代码段第三行的else之前有两个未被配对的if,这个else到底该属于哪个if?C语言规定,每个else总是与离其最近的未被配对的if配对。所以上例中,第一个else应该与第二个if配对,即使程序员的意思想让它和第一个if配对,并且也按照错格的方式让它与第一个if对齐了,但是它依然和第二个if配对。最好的解决办法就是加花括号,若上述语句块格式改为:
则使得第一个else与第一个if配对了。所以正确地使用花括号是写if语句时应特别注意的问题。
解决方案2:使用逻辑表达式
可以用逻辑表达式来判断某个年份是否符合闰年条件:能被4整除,但不能被100整除,或能被400整除。
(year%400==0)|| ((year%4==0)&& (year%100 !=0))
此式与
year%400==0 || year%4==0 && year%100 !=0
是等价的,但前者加上括号后计算的先后顺序一目了然,即使忘记了各种运算符的优先级也能计算出正确的结果。
核心代码段如下: