C 语言 if 语句简介

目录汇总:C 语言零基础入门教程

if 语句允许程序通过测试表达式的值从两种选项中选择一种。if 语句的最简单格式如下:

1
[if语句] if (表达式) 语句

注意,表达式两边的圆括号是必需的,它们是 if 语句的组成部分,而不是表达式的内容。还要注意,与在其他一些语言中的用法不同,单词 then 没有出现在圆括号的后边。

执行 if 语句时,先计算圆括号内表达式的值。如果表达式的值非零(C 语言把非零值解释为真值),那么接着执行圆括号后边的语句。下面是一个示例:

1
2
if (line_num == MAX_LINES)
  line_num = 0;

如果条件 line_num == MAX_LINES 为真(有非零值),那么执行语句 line_num = 0;

注意

不要混淆 ==(判等)运算符和 =(赋值)运算符。语句 if (i == 0)... 测试i是否等于 0,而语句 if (i = 0)... 则是先把 0 赋值给 i,然后测试赋值表达式的结果是否是非零值。在这种情况下,测试总是会失败的。

== 运算符与 = 运算符相混淆是最常见的 C 语言编程错误,这也许是因为 = 在数学(和其他许多编程语言)中意味着“等于”。如果注意到通常应该出现运算符 == 的地方出现的是运算符 =,有些编译器会给出警告。

通常,if 语句中的表达式能判定变量是否落在某个数值范围内。例如,为了判定 0≤i<n 是否成立,可以写成

1
[惯用法] if (0 <= i && i < n)...

为了判定相反的情况(i 在此数值范围之外),可以写成

1
[惯用法] if (i < 0 || i >= n)...

注意用运算符 || 代替运算符 &&

一、复合语句

注意,在 if 语句模板中,语句是一条语句而不是多条语句:

1
if (表达式) 语句

如果想用 if 语句处理两条或更多条语句,该怎么办呢?可以引入复合语句(compound statement)。复合语句由一对花括号,以及花括号内的声明和语句混合而成。可以有多个声明和多条语句,也可以都没有。在后一种情况下,复合语句只有一对花括号,它什么也不做。典型地,通过在一组语句周围放置花括号,可以强制编译器将其作为一条语句来处理。

下面是一个复合语句的示例:

1
{ line_num = 0; page_num++; }

为了表示清楚,通常将一条复合语句放在多行内,每行有一条语句,如下所示:

1
2
3
4
{ 
  line_num = 0;
  page_num++;
}

注意,每条内部语句仍然是以分号结尾的,但复合语句本身并不是。

下面是在 if 语句内部使用复合语句的形式:

1
2
3
4
if (line_num == MAX_LINES) {
  line_num = 0;
  page_num++;
}

复合语句也常出现在循环和其他需要多条语句(但 C 语言的语法要求一条语句)的地方。

二、else 子句

if 语句可以有 else 子句:

1
[带有else子句的if语句] if (表达式) 语句 else 语句

如果圆括号内的表达式的值为 0,那么就执行 else 后边的语句。

下面是一个含有 else 子句的 if 语句的示例:

1
2
3
4
if (i > j)
  max = i;
else
  max = j;

注意,两条“内部”语句都是以分号结尾的。

if 语句包含 else 子句时,出现了布局问题:应该把 else 放置在哪里呢?和前面的例子一样,许多 C 程序员把它和 if 对齐排列在语句的起始位置。内部语句通常采用缩进格式;但是,如果内部语句很短,可以把它们与 ifelse 放置在同一行中:

1
2
if (i > j) max = i;
else max = j;

C 语言对可以出现在 if 语句内部的语句类型没有限制。事实上,在 if 语句内部嵌套其他 if 语句是非常普遍的。考虑下面的 if 语句,其功能是找出 ijk 中所存储的最大值并将其保存到 max 中:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
if (i > j)
  if (i > k)
    max = i;
  else
    max = k;
else
  if (j > k)
    max = j;
  else
    max = k;

if 语句可以嵌套任意层。注意,把每个 else 同与它匹配的 if 对齐排列,这样做很容易辨别嵌套层次。如果发现嵌套仍然很混乱,那么不要犹豫,直接增加花括号就可以了:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
if (i > j) {
  if (i > k)
    max = i;
  else
    max = k;
} else {
  if (j > k)
    max = j;
  else
    max = k;
}

为语句增加花括号(即使有时并不是必需的)就像在表达式中使用圆括号一样,这两种方法都可以使程序更加容易阅读,同时可以避免出现编译器不能像程序员一样去理解程序的问题。

有些程序员在 if 语句(以及重复语句)中尽可能多地使用花括号。遵循这种惯例的程序员为每个 if 子句和每个 else 子句都使用一对花括号:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
if (i > j) {
  if (i > k){
    max = i;
  } else {
    max = k;
  }
} else {
  if (j > k) {
    max = j;
  } else {
    max = k;
  }
}

即便在不必要的情况下也使用花括号,这样做有两个好处。首先,由于很容易添加更多的语句到任何 ifelse 子句中,程序变得更容易修改;其次,这样做可以在向 ifelse 子句中增加语句时避免由于忘记使用花括号而导致错误。

三、级联式 if 语句

编程时常常需要判定一系列的条件,一旦其中某一个条件为真就立刻停止。“级联式”if 语句常常是编写这类系列判定的最好方法。例如,下面这个级联式 if 语句用来判定 n 是小于 0、等于 0,还是大于 0:

1
2
3
4
5
6
7
if (n < 0)
  printf("n is less than 0\n");
else
  if (n == 0)
    printf("n is equal to 0\n");
  else
    printf("n is greater than 0\n");

虽然第二个 if 语句是嵌套在第一个 if 语句内部的,但是 C 语言程序员通常不会对它进行缩进,而是把每个 else 都与最初的 if 对齐:

1
2
3
4
5
6
if (n < 0)
  printf("n is less than 0\n");
else if (n == 0)
  printf("n is equal to 0\n");
else
  printf("n is greater than 0\n");

这样的安排带给级联式 if 语句独特的书写形式:

1
2
3
4
5
6
7
8
9
if (表达式)
  语句
else if (表达式)
  语句
...
else if (表达式)
  语句
else
  语句

当然,这种格式中的最后两行(else 语句)不是总出现的。这种缩进级联式 if 语句的方法避免了判定数量过多时过度缩进的问题。此外,这样也向读者证明了这组语句只是一连串的判定。

请记住,级联式 if 语句不是新的语句类型,它仅仅是普通的 if 语句,只是碰巧有另外一条 if 语句作为 else 子句(而且这条 if 语句又有另外一条 if 语句作为它自己的 else 子句,以此类推)。

程序 计算股票经纪人的佣金

当股票通过经纪人进行买卖时,经纪人的佣金往往根据股票交易额采用某种变化的比例进行计算。表 4 显示了实际支付给经纪人的费用金额。

表 4 支付股票经纪人实际费用

交易额范围 佣金
低于2500美元 330美元 + 1.7%
2500~6250美元 356美元 + 0.66%
6250~20 000美元 376美元 + 0.34%
20 000~50 000美元 100美元 + 0.22%
50 000~500 000美元 155美元 + 0.11%
超过500 000美元 255美元 + 0.09%

最低收费是 39 美元。下面的程序要求用户输入交易额,然后显示出佣金的数额:

Enter value of trade: 30000
Commission: $166.00

该程序的重点是用级联式 if 语句来确定交易额所在的数值范围。

broker.c

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/* Calculates a broker's commission */

#include <stdio.h>

int main(void)
{
 float commission, value;

 printf("Enter value of trade: ");
 scanf("%f", &value);

 if (value < 2500.00f)
   commission = 30.00f + .017f * value;
 else if (value < 6250.00f)
   commission = 56.00f + .0066f * value;
 else if (value < 20000.00f)
   commission = 76.00f + .0034f * value;
 else if (value < 50000.00f)
   commission = 100.00f + .0022f * value;
 else if (value < 500000.00f)
   commission = 155.00f + .0011f * value;
 else
   commission = 255.00f + .0009f * value;

 if (commission < 39.00f)
   commission = 39.00f;

 printf("Commission: $%.2f\n", commission);

 return 0;
}

级联式 if 语句也可以写成下面这样(改变用粗体表示):

if (value < 2500.00f)
 commission = 30.00f + .017f * value;
else if (value >= 2500.00f && value < 6250.00f)
 commission = 56.00f + .0066f * value;
else if (value >= 6250.00f && value < 20000.00f)
 commission = 76.00f + .0034f * value;
...

程序仍能正确运行,但新增的这些条件是多余的。例如,第一个 if 子句测试 value 的值是否小于 2500,如果小于 2500 则计算佣金。当到达第二个 if 测试 (value >= 2500.00f && value < 6250.00f) 时,value 不可能小于 2500,因此一定大于等于 2500。条件 value >= 2500.00f 总是为真,因此加上该测试没有意义。

四、“悬空 else”的问题

if 语句嵌套时,千万要当心著名的“悬空 else”的问题。思考下面这个例子:

1
2
3
4
5
if (y != 0)
  if (x != 0)
    result = x / y;
else
  printf("Error: y is equal to 0\n");

上面的 else 子句究竟属于哪一个 if 语句呢?缩进格式暗示它属于最外层的 if 语句。然而,C 语言遵循的规则是 else 子句应该属于离它最近的且还未和其他 else 匹配的 if 语句。在此例中,else 子句实际上属于最内层的 if 语句,因此正确的缩进格式应该如下所示:

1
2
3
4
5
if (y != 0)
  if (x != 0)
    result = x / y;
  else
    printf("Error: y is equal to 0\n");

为了使 else 子句属于外层的 if 语句,可以把内层的 if 语句用花括号括起来:

1
2
3
4
5
if (y != 0) {
  if (x != 0)
    result = x / y;
} else
    printf("Error: y is equal to 0\n");

这个示例表明了花括号的作用。如果把花括号用在本节第一个示例的 if 语句上,那么就不会有这样的问题了。

五、条件表达式

C 语言的 if 语句允许程序根据条件的来执行两个操作中的一个。C 语言还提供了一种特殊的运算符,这种运算符允许表达式依据条件的值产生两个值中的一个。

条件运算符(conditional operator)由符号 ? 和符号 : 组成,两个符号必须按如下格式一起使用:

1
[条件表达式] 表达式1 ? 表达式2 : 表达式3

表达式1表达式2表达式3可以是任何类型的表达式,按上述方式组合成的表达式称为条件表达式(conditional expression)。条件运算符是 C 运算符中唯一一个要求 3 个操作数的运算符。因此,它通常被称为三元(ternary)运算符。

应该把条件表达式表达式1?表达式2:表达式3读作“如果表达式1成立,那么表达式2,否则表达式3”。条件表达式求值的步骤如下:首先计算出表达式1的值,如果此值不为零,那么计算表达式2的值,并且计算出来的值就是整个条件表达式的值;如果表达式1的值为零,那么表达式3的值是整个条件表达式的值。

下面的示例对条件运算符进行了演示:

1
2
3
4
5
6
int i, j, k;

i = 1;
j = 2;
k = i > j ? i : j;               /* k is now 2 */
k = (i >= 0 ? i : 0) + j;        /* k is now 3 */

在第一个对 k 赋值的语句中,条件表达式 i > j ? i : j 根据 ij 的大小关系返回其中一个的值。因为 i 的值为 1、j 的值为 2,表达式 i > j 比较的结果为假,所以条件表达式的值 2 被赋给 k。在第二个对 k 赋值的语句中,因为表达式 i >= 0 比较的结果为真,所以条件表达式 (i >= 0 ? i : 0) 的值为 1,然后把这个值和 j 相加得到结果 3。顺便说一下,这里的圆括号是非常必要的,因为除赋值运算符以外,条件运算符的优先级低于先前介绍过的所有运算符。

条件表达式使程序更短小但也更难以阅读,因此最好避免使用。然而,在少数地方仍会使用条件表达式,其中一个就是 return 语句。许多程序员把

1
2
3
4
if (i > j)
  return i;
else
  return j;

替换为

1
return i > j ? i : j;

printf 函数的调用有时会得益于条件表达式。代码

1
2
3
4
if (i > j)
  printf("%d\n", i);
else
  printf("%d\n", j);

可以简化为

1
printf("%d\n", i > j ? i : j);

六、C89 中的布尔值

多年以来,C 语言一直缺乏适当的布尔类型,C89 标准中也没有定义布尔类型。因为许多程序需要变量能存储假或真值,所以缺少布尔类型可能会有点麻烦。针对 C89 的这一限制,一种解决方法是先声明一个 int 型变量,然后将其赋值为 0 或 1:

1
2
3
4
5
int flag;

flag = 0;
...
flag = 1;

虽然这种方法可行,但是它对程序的可读性没有多大贡献。这是因为该方法没有明确地表示 flag 的赋值只能是布尔值,并且也没有明确地指出 0 和 1 就是表示假和真。

为了使程序更易于理解,C89 的程序员通常使用 TRUEFALSE 这样的名字定义宏:

1
2
#define TRUE 1
#define FALSE 0

现在对 flag 的赋值有了更加自然的形式:

1
2
3
flag = FALSE;
...
flag = TRUE;

为了判定 flag 是否为真,可以用

1
if (flag == TRUE) ...

或者只写

1
if (flag) ...

后一种形式更好,一是它更简洁,二是当 flag 的值不是 0 或 1 时程序也能正确运行。

为了判定 flag 是否为假,可以用

1
if (flag == FALSE) ...

或者

1
if (!flag) ...

为了发扬这一思想,甚至可以定义一个可用作类型的宏:

1
#define BOOL int

声明布尔变量时可以用 BOOL 代替 int

1
BOOL flag;

现在就非常清楚 flag 不是普通的整型变量,而是表示布尔条件。(当然,编译器仍然把 flag 看作 int 型变量。)在后面的 C 语言零基础入门教程 中,我们将介绍一些更好的方法,可以使用类型定义和枚举在 C89 中设置布尔类型。

七、C99 中的布尔值

长期缺乏布尔类型的问题在 C99 中得到了解决。 C99 提供了 _Bool 型,因此在 C 语言的这一版本中,布尔变量可以声明为

1
_Bool flag;

_Bool 是整数类型(更准确地说是无符号整型),因此 _Bool 变量实际上就是整型变量;但是和一般的整型不同,_Bool 只能赋值为 0 或 1。一般来说,往 _Bool 变量中存储非零值会导致变量赋值为 1:

1
flag = 5;  /* flag is assigned 1 */

对于 _Bool 变量来说,算术运算是合法的(不过不建议这样做),它的值也可以被打印出来(显示 0 或者 1)。当然,_Bool 变量也可以在 if 语句中测试:

1
2
if (flag)  /* tests whether flag is 1 */
  ...

除了 _Bool 类型的定义,C99 还提供了一个新的头 <stdbool.h>,这使得操作布尔值更加容易。该头提供了 bool 宏,用来代表 _Bool。如果程序中包含了 <stdbool.h>,可以这样写:

1
bool flag;  /* same as _Bool flag; */

<stdbool.h> 头还提供了 truefalse 两个宏,分别代表 1 和 0。于是可以写

1
2
3
flag = false;
...
flag = true;

<stdbool.h> 头使用起来非常方便,因此在后面的程序中需要使用布尔变量时都用到了这个头。

请参阅

(完)

comments powered by Disqus