8.2 if else语句

C语言学习栏目目录

目录

else与if配对

 多层嵌套的if语句


源码

简单形式的if语句可以让程序选择执行一条语句,或者跳过这条语句。C还提供了if else形式,可以在两条语句之间作选择。我们用if else形式修正上一节(8.1 if语句)中程序清单的程序段。

if (all_days != 0)
    printf("总共 %d 天: %.1f%% 的时间低于零下.\n",all_days, 100.0 * (float)cold_days / all_days);
if (all_days == 0)
    printf("没有数据输入!\n");

如果程序发现all_days不等于0,那么它应该知道另一种情况一定是all_days等于0。用if else形式只需测试一次。重写上面的程序段如下:

if (all_days!= 0)
    printf("总共 %d 天: %.1f%% 的时间低于零下.\n",all_days, 100.0 * (float)cold_days / all_days);
else
    printf("没有数据输入!\n");

如果if语句的测试表达式为真,就打印温度数据;如果为假,就打印警告消息。

注意,if else语句的通用形式是:

if ( expression )
    statement1
else
    statement2

如果expression为真(非0),则执行statement1;如果expression为假或0,则执行else后面的statement2。statement1和statement2可以是一条简单语句或复合语句。C并不要求一定要缩进,但这是标准风格。缩进让根据测试条件的求值结果来判断执行哪部分语句一目了然。

如果要在if和else之间执行多条语句,必须用花括号把这些语句括起来成为一个块。下面的代码结构违反了C语法,因为在if和else之间只允许有一条语句(简单语句或复合语句):

if (x > 0)
    printf("递增 x:\n");
x++;
else   // 将产生一个错误
    printf("x <= 0 \n");

编译器把printf()语句视为if语句的一部分,而把x++;看作一条单独的语句,它不是if语句的一部分。然后,编译器发现else并没有所属的if,这是错误的。上面的代码应该这样写:

if (x > 0)
{
    printf("递增 x:\n");
    x++;
}
else
    printf("x <= 0 \n");

if语句用于选择是否执行一个行为,而else  if语句用于在两个行为之间
选择。下图比较了这两种语句。

 

else与if配对

如果程序中有许多if和else,编译器如何知道哪个if对应哪个else?例如,考虑下面的程序段:

if (number > 6)
if (number < 12)
    printf("你很接近了!\n");
else
    printf("对不起,你掉队了!\n");

何时打印"对不起,你掉队了"?当number小于或等于6时,还是number大于12时?换言之,else与第1个if还是第2个if匹配?答案是,else与第2个if匹配。也就是说,输入的数字和匹配的响应如下:

数字   响应
5     无
10    你接近了!
15    对不起,就你掉队了!

规则是,如果没有花括号,else与离它最近的if匹配,除非最近的if被花括号括起来

注意:要缩进“语句”,“语句”可以是一条简单语句或复合语句。

第1个例子的缩进使得else看上去与第1个if相匹配,但是记住,编译器是忽略缩进的。如果希望else与第1个if匹配,应该这样写:

if (number > 6)
{
    if (number < 12)
        printf("You're close!\n");
}
else
    printf("Sorry, you lose a turn!\n");

这样改动后,响应如下: 


数字   响应
5     对不起,你掉队了!
10    你很接近了!
15    无

 多层嵌套的if语句

前面介绍的if...else if...else序列是嵌套if的一种形式,从一系列选项中选择一个执行。有时,选择一个特定选项后又引出其他选择,这种情况可以使用另一种嵌套 if。例如,程序可以使用 if else选择男女,if else的每个分支里又包含另一个if else来区分不同收入的群体。

我们把这种形式的嵌套if应用在下面的程序中。给定一个整数,显示所有能整除它的约数。如果没有约数,则报告该数是一个素数。

在编写程序的代码之前要先规划好。首先,要总体设计一下程序。为方便起见,程序应该使用一个循环让用户能连续输入待测试的数。这样,测试一个新的数字时不必每次都要重新运行程序。下面是我们为这种循环开发的一个模型(伪代码):

提示用户输入数字

当scanf()返回值为1

分析该数并报告结果

提示用户继续输入

回忆一下在测试条件中使用scanf(),把读取数字和判断测试条件确定是否结束循环合并在一起。

下一步,设计如何找出约数。也许最直接的方法是:

for (div = 2; div < num; div++)
    if (num % div == 0)
        printf("%d is divisible by %d\n", num, div);

 该循环检查2~num之间的所有数字,测试它们是否能被num整除。但是,这个方法有点浪费时间。我们可以改进一下。例如,考虑如果144%2得0,说明2是144的约数;如果144除以2得72,那么72也是144的一个约数。所以,num % div测试成功可以获得两个约数。为了弄清其中的原理,我们分析一下循环中得到的成对约数:2和72、2和48、4和36、6和24、8和18、9和
16、12和12、16和9、18和8,等等。在得到12和12这对约数后,又开始得到已找到的相同约数(次序相反)。因此,不用循环到143,在达到12以后就可以停止循环。这大大地节省了循环时间!

分析后发现,必须测试的数只要到num的平方根就可以了,不用到num。对于9这样的数字,不会节约很多时间,但是对于10000这样的数,使用哪一种方法求约数差别很大。不过,我们不用在程序中计算平方根,可以这样编写测试条件:

for (div = 2; (div * div) <= num; div++)
    if (num % div == 0)
        printf("%d is divisible by %d and %d.\n",num, div, num / div);

如果num是144,当div = 12时停止循环。如果num是145,当div = 13时停止循环。不使用平方根而用这样的测试条件,有两个原因。其一,整数乘法比求平方根快。其二,我们还没有正式介绍平方根函数。还要解决两个问题才能准备编程。第1个问题,如果待测试的数是一个完全平方数怎么办?报告144可以被12和12整除显得有点傻。可以使用嵌套if语句测试div是否等于num /div。如果是,程序只打印一个约数:

for (div = 2; (div * div) <= num; div++)
{
    if (num % div == 0)
    {
        if (div * div != num)
            printf("%d is divisible by %d and %d.\n",num, div, num / div);
        else
            printf("%d is divisible by %d.\n", num, div);
    }
}

注意从技术角度看,if else语句作为一条单独的语句,不必使用花括号。外层if也是一条单独的语句,也不必使用花括号。但是,当语句太长时,使用花括号能提高代码的可读性,而且还可防止今后在if循环中添加其他语句时忘记加花括号。

第2个问题,如何知道一个数字是素数?如果num是素数,程序流不会进入if语句。要解决这个问题,可以在外层循环把一个变量设置为某个值(如,1),然后在if语句中把该变量重新设置为0。循环完成后,检查该变量是否是1,如果是,说明没有进入if语句,那么该数就是素数。这样的变量通常称为标记(flag)。

一直以来,C都习惯用int作为标记的类型,其实新增的_Bool类型更合适。另外,如果在程序中包含了stdbool.h头文件,便可用bool代替_Bool类型,用true和false分别代替1和0。下程序清单体现了以上分析的思路。为扩大该程序的应用范围,程序用long类型而不是int类型(如果系统不支持_Bool类型,可以把isPrime的类型改为int,并用1和0分别替换程序中的true和false)。


/************************************************************************
功能:使用嵌套if语句显示一个数的约数                                                              
/************************************************************************/

#include <stdio.h>
#include <stdbool.h>
int main(void)
{
	unsigned long num;			// 待测试的数
	unsigned long div;			// 可能的约数
	bool isPrime;				// 素数标记
	printf("请输入待分析整数进行分析; ");
	printf("按q退出.\n");
	while (scanf("%lu", &num) == 1)
	{
		for (div = 2, isPrime = true; (div * div) <= num; div++)
		{
			if (num % div == 0)
			{
				if ((div * div) != num)
					printf("%lu 可被 %lu 和 %lu 整除.\n",num, div, num / div);
				else
					printf("%lu 可被 %lu 整除.\n",
						num, div);
				isPrime = false;		// 该数不是素数
			}
		}
		if (isPrime)
			printf("%lu 是质数.\n", num);
		printf("请输入待分析整数进行分析; ");
		printf("按q退出.\n");
	}
	printf("再见.\n");
	return 0;
}

注意,该程序在for循环的测试表达式中使用了逗号运算符,这样每次输入新值时都可以把isPrime设置为true。下面是该程序的一个输出示例:

请输入待分析整数进行分析; 按q退出.
123456789
123456789 可被 3 和 41152263 整除.
123456789 可被 9 和 13717421 整除.
123456789 可被 3607 和 34227 整除.
123456789 可被 3803 和 32463 整除.
123456789 可被 10821 和 11409 整除.
请输入待分析整数进行分析; 按q退出.
149
149 是质数.
请输入待分析整数进行分析; 按q退出.
2013
2013 可被 3 和 671 整除.
2013 可被 11 和 183 整除.
2013 可被 33 和 61 整除.
请输入待分析整数进行分析; 按q退出.
q
再见.

该程序会把1认为是素数,其实它不是。下一节将要介绍的逻辑运算符可以排除这种特殊的情况。

小结:用if语句进行选择

关键字:if、else

一般注解:

下面各形式中,statement可以是一条简单语句或复合语句。表达式为真

说明其值是非零值。

形式1:

if (expression)
    statement

如果expression为真,则执行statement部分。

形式2:

if (expression)
    statement1
else
    statement2

如果expression为真,执行statement1部分;否则,执行statement2部分。

形式3:

if (expression1)
    statement1
else if (expression2)
    statement2
else
    statement3

如果expression1为真,执行statement1部分;如果expression2为真,执行statement2部分;否则,执行statement3部分

 

©️2020 CSDN 皮肤主题: 猿与汪的秘密 设计师:上身试试 返回首页