2. if/else语句

if语句还可以带一个else子句(Clause),例如:

if (x % 2 == 0)
	printf("x is even.\n");
else
	printf("x is odd.\n");

这里的%是取模(Modulo)运算符,x%2表示x除以2所得的余数(Remainder),%运算符的两个操作数必须是整型。第 5 节 “表达式”讲过,如果/运算符的两个操作数都是整数,则结果是两数的商(Quotient),余数总是舍去,因此有如下结论成立:a和b是两个整数,b不等于0,(a/b)*b+a%b总是等于a。

取模运算在程序中是非常有用的,例如上面的例子判断x的奇偶性(Parity),看x除以2的余数是不是0,如果是0则打印x is even.,如果不是0则打印x is odd.,读者应该能看出else在这里的作用了,如果上面的例子去掉else,不管x是奇是偶,x is odd.这一句总是被打印。为了让这条语句更有用,可以把它封装(Encapsulate)成一个函数:

void print_parity(int x)
{
	if (x % 2 == 0)
		printf("x is even.\n");
	else
		printf("x is odd.\n");
}

把语句封装成函数的基本步骤是:把语句放到函数体中,把变量改成函数的参数。这样,以后要检查一个数的奇偶性只需调用这个函数而不必重复写这条语句了,例如:

print_parity(17);
print_parity(18);

if/else语句的格式为:

if (控制表达式)
	语句
else
	语句

同样道理,其中的“语句”既可以是一条语句,也可以是由{}括起来的语句块。从这里我们又看到了组合规则:一条if语句中包含一条子语句,一条if/else语句中包含两条子语句,子语句可以是任何语句,当然也可以是另外一条ifif/else,子语句还可以是{}括起来的语句块,其中又可以包含任何语句,当然也可以包含另外一条ifif/else。根据组合规则,ifif/else可以嵌套使用。例如可以这样:

if (x > 0)
	printf("x is positive.\n");
else if (x < 0)
	printf("x is negative.\n");
else
	printf("x is zero.\n");

也可以这样:

if (x > 0) {
	printf("x is positive.\n");
} else {
	if (x < 0)
		printf("x is negative.\n");
	else
		printf("x is zero.\n");
}

现在有一个问题,类似if (A) if (B) C; else D;形式的语句怎么理解呢?可以理解成

if (A)
	if (B)
		C;
else
	D;

也可以理解成

if (A)
	if (B)
		C;
	else
		D;

第 1 节 “继续Hello World”中讲过,在C语言中缩进只是为了程序员看起来方便,实际上对编译器不起任何作用,你的代码不管写成上面哪一种缩进格式,在编译器看起来都是一样的。那么编译器到底认为是哪一种理解呢?也就是说,else到底是和if (A)配对还是和if (B)配对?很多编程语言都有这个问题,这称为Dangling-else问题。C语言规定,else总是和它上面最近的一个if配对,因此应该理解成elseif (B)配对,也就是上面第二种理解。如果你写成上面第一种缩进的格式就很危险了:你看到的是这样,而编译器理解的却是那样。如果你希望的是第一种理解,应该明确加上{}:

if (A) {
	if (B)
		C;
} else
	D;

习题

1、写两个表达式,分别取整数x的个位和十位

2、写一个函数,参数是整数x,功能是打印参数x的个位和十位