目录
传送门-上一节:C语言程序设计-关系运算符和关系表达式、逻辑运算符和逻辑表达式
传送门-下一节:C语言程序设计-if语句和switch语句的进阶、条件运算符和表达式
3.3 if语句
前面两章所介绍的程序都属于顺序结构,顺序结构程序中的所有语句都将被执行一次。但是在实际应用中,常常需要根据不同情况选择执行不同的语句,这时需要设计分支结构程序来实现,例如,学生成绩不低于60分就算通过,否则按不通过处理。在C语言中,通常用if语句、switch语句或条件表达式解决分支结构问题。本节将分别介绍if语句和switch语句,在3.6.2节中介绍条件表达式。分支结构逻辑性较强,使用时有一定的难度,希望读者认真学习本章介绍的所有内容,并自己动手编写程序,加强上机实践。
3.3.1 if语句的一般形式
if语句有两种形式。
1. 不带else的if语句
【例 3.4】任意输入两个整数存放在变量a、b中,输出时保证a中的值不比b中的值大。编写程序实现其功能。
#include<stdio.h>
void main()
{
int a = 0, b = 0, t = 0;
printf("Input a,b:");
scanf("%d%d", &a, &b);
if (a > b) //如果a的值比b的值大,交换a和b的值
{
t = a;
a = b;
b = t;
}
printf("a=%d,b=%d\n", a, b);
}
第一次运行结果:(a和b的值不变)
Input a,b:2 5
a=2,b=5
第二次运行结果:(a和b的值被交换)
Input a,b:5 2
a=2,b=5
程序说明:
(1)从以上两次的运行情况可以看出,3条语句“t=a;a=b;b=t;”是if的子句,当表达式a>b为“真”时,要执行“t=a;a=b;b=t;”;为“假”时,不执行。
(2)由于3条语句“t=a;a=b;b=t;”是if语句的一部分,因此要求像本程序中那样,书写时缩进几个格,以此体现它们之间的隶属关系,提高程序的可读性,这一点对初学者十分重要。
(3)由于本题有两种可能,所以在得到第一次运行结果后还不能断定程序是否正确,必须通过第二批数据的测试。也就是说,如果程序中有多个分支的情况,必须对每一分支进行数据测试,才能确保程序无误。
不带else的if语句形式如下:
if(表达式)
{子句}
说明:
(1)if是关键字,if后面的表达式可以是任意合法表达式。例如,x>5、x==5、x=5、x+5、x、5等。不管是何种表达式,都要先计算该表达式的值,再根据其结果的非零或零来判断表达式是”真“还是”假“。
(2)x==0和x=0是两个不同的表达式,当x的值为0时,前一个表达式的值为1(表示为“真”),后一个表达式的值为0(表示为“假”),因此编写程序时一定要分清是用“==”还是用“=”。
(3)在if语句格式中将if子句用花括号括起来了,这是因为if子句语法上要求一条语句,而用花括号括起来的多条语句(称为复合语句),在语法上当作一条语句。当if子句只包含一条语句时,一对花括号可以省略。
(4)第一种if语句的执行过程是:先计算表达式的值,若表达式的计算结果为非零数,则执行if子句,否则跳过if子句(如图3.1所示)。
图3.1 不带else的if语句执行过程
【例 3.5】 编写输出如下分段函数值得程序,要求整数x的值从键盘输入。
【解】 编程点拨:
本例题需要根据x的4个不同取值范围找出相应的C语言表达式,然后使用4条if语句实现相应的功能。程序如下:
#include<stdio.h>
void main()
{
int x = 0;
double y = 0.0;
printf("Input x:");
scanf("%d", &x);
if (x < 0) //如果x<0,执行y=x-2;否则跳过此语句
y = x - 2;
if (x == 0) //如果x=0,执行y=1.0;否则跳过此语句
y = 1.0;
if (x > 0 && x <= 3) //如果0<x<=3,执行y=2.0*x;否则跳过此语句
y = 2.0 * x;
if (x > 3) //如果x>3,执行y=x/3.0;否则跳过此语句
y = x / 3.0;
printf("x=%d,y=%lf\n", x, y);
}
第一次运行结果:
Input x:-5
x=-5,y=-7.000000
第二次运行结果:
Input x:0
x=0,y=1.000000
第三次运行结果:
Input x:2
x=2,y=4.000000
第四次运行结果:
Input x:8
x=8,y=2.666667
程序说明:
(1)运行程序时,通过输入4类数据分别对每一种情况进行了验证。
(2)上面的程序可改写为如下形式,但此时没把计算所得的函数值存起来:
#include<stdio.h>
void main()
{
int x = 0;
printf("Input x:");
scanf("%d", &x);
if (x < 0) printf("x=%d,y=%lf\n", x, x - 2);
if (x == 0) printf("x=%d,y=%lf\n", x, 1.0);
if (x > 0 && x <= 3) printf("x=%d,y=%lf\n", x, 2.0 * x);
if (x > 3) printf("x=%d,y=%lf\n", x, x / 3.0);
}
【例 3.6】输入3个整数,输出其中最大数。
【解】编程点拨:
先举一个例题。擂台赛:谁赢谁上奖台;只有一个人时,他自然就站在奖台上;来了第二个人,他需要跟奖台上的人进行比赛,谁赢谁上奖台;又来了第三个人,他又需要跟奖台上的人进行比赛,谁赢谁上奖台;以此类推,最终站在奖台上的一定是冠军。
图3.2 例3.6的流程图
本题的算法与上面思路类似,其算法用图3.2表示,其中max相当于奖台,a、b、c相当于3个人,最后max中存放3个数中的最大值。程序如下:
#include<stdio.h>
void main()
{
int a = 0, b = 0, c = 0, max = 0;
printf("Input a,b,c:");
scanf("%d%d%d", &a, &b, &c);
max = a; //max内存放a的值
if (max < b)max = b; //max内存放a、b中较大的值
if (max < c)max = c; //max内存放a、b、c中较大的值
printf("a=%d,b=%d,c=%d,max=%d\n", a, b, c, max);
}
第一次运行结果:
Input a,b,c:3 5 7
a=3,b=5,c=7,max=7
第二次运行结果:
Input a,b,c:9 5 7
a=9,b=5,c=7,max=9
第三次运行结果:
Input a,b,c:3 8 7
a=3,b=8,c=7,max=8
程序说明:
max是为存放最大值开辟的变量,变量名可以按照其命名规则随意起名,在本例中为了达到见名知意的效果,选择max为其变量名。
【例 3.7】输入3个不同的整数,分别存放在a、b、c中,再把这3个数按从小到大的顺序重新放入a、b、c,然后输出。
【解】编程点拨:
3个数从小到大顺序排列的算法类似于3个小孩由矮到高排队。本题可以按以下步骤进行:
(1)比较前两个数。如果后面的数比前面的小,两个数交换,否则不交换,如图3.4(a)所示。
(2)第二个数(前两个数中大者)与最后一个比大小。如果最后一个比第二个小,则这两个数交换,否则不交换,这时最后面的数是3个数中最大值(冒第一个泡7,如图3.4(b)所示)。
(3)前两个数进行比较。如果后面的数比前面的小,则两个数交换,否则不交换。这时中间的数次大(冒第二个泡6,如图3.4(c)所示),自然第一个数最小。
图3.4 3个数排序过程
这种算法被称为冒泡法。其程序如下:
#include<stdio.h>
void main()
{
int a = 0, b = 0, c = 0, temp = 0;
printf("Input a,b,c:");
scanf("%d%d%d", &a, &b, &c);
printf("Before:a=%d,b=%d,c=%d\n", a, b, c);
if(a > b) //执行if语句后,b内存放a和b中较大数
{
temp = a; a = b; b = temp;
}
if (b > c) //执行if语句后,c内存放3数中最大数
{
temp = b; b = c; c = temp;
}
if (a > b) //执行if语句后,b内存放3数中次大数
{
temp = a; a = b; b = temp;
}
printf("After:a=%d,b=%d,c=%d\n", a, b, c);
}
运行结果:
Input a,b,c:7 6 5
Before:a=7,b=6,c=5
After:a=5,b=6,c=7
程序说明:
(1)if子句语法上要求一条语句,如果语句多于一条,就用花括号把它们括起来。用花括号括起来的多条语句称为复合语句,复合语句在语法上当作一条语句。
(2)if语句“if(a > b) {temp = a; a = b; b = temp;}”是一条语句。如果将此语句写成“if(a > b) {temp = a; a = b; b = temp;};”即在花括号后面加一个分号,则变成两条语句:一条if语句和一条空语句,仅由分号构成的语句称为空语句。如果将上面if语句写成“if(a > b) ;{temp = a; a = b; b = temp;}”也变成两条语句:一条if语句(if子句为空语句)和一个复合语句。其作用是:如果a>b,则先执行空语句,再执行符合语句;否则,直接执行复合语句。由于空语句不产生任何效果,不管a的值是否比b的值大,都要执行复合语句,两种效果相同。这导致与原if语句作用不同。
(3)本程序只给出一种情况的运行结果,请读者自行测试其他各种情况,并建议用单步执行的方法观察程序中a、b、c的变化情况。
2. 带else的if语句
【例 3.8】输入一个整数,如果是偶数,则输出Even number;如果是奇数,则输出Odd number.
【解】程序如下:
#include<stdio.h>
void main()
{
int a = 0;
printf("Input a : ");
scanf("%d", &a);
if (a % 2 == 0) //如果a的值是偶数
printf("Even number\n"); //输出Even number
else //否则
printf("Odd number\n"); //输出Odd number
}
第一次运行结果:
Input a : 16
Even number
第二次运行结果:
Input a : 5
Odd number
程序说明:
如果a的值是偶数,则表达式a%2==0的值为1,是非0值,因此执行语句“printf("Even number\n");”,如果a的值是奇数,则表达式a%2==0的值为0,因此执行语句“printf("Odd number\n");”。
if-else的语句形式如下:
if(表达式)
{ if子句 }
else
{ else子句 }
说明:
(1)if和else都是关键字,else必须与if配对使用。if子句和else子句都用花括号括起来当作一条语句,当if子句或else子句只包含一条语句时,可将对应的花括号省略。
(2)if-else语句的执行过程是:先计算表达式的值,若表达式的结果为非零值,则执行if子句,否则执行else子句(如图3.5所示)。
图3.5 带else的if语句执行过程
(3)使用if语句时,不要随意加分号,否则会产生错误语法或导致语句作用不同。例如若将本例中的if语句写成
if (a % 2 == 0); //多加了分号,所以if语句到此结束
printf("Even number\n"); //此语句变成了if语句的下一条语句
else //没有配对的if
printf("Odd number\n");
则导致语法错误;若改写成
if (a % 2 == 0)
printf("Even number\n");
else; //多加了分号,所以if语句到此结束
printf("Odd number\n"); //此语句变成了if语句的下一条语句
则虽然没有语法错误,但语句作用不同。
3.3.2 if语句的嵌套
在if语句或else子句中还可以包含另一个if语句,这样的if语句称为嵌套的if语句。
【例 3.9】编写含有嵌套if语句的程序。
【解】程序如下:
#include<stdio.h>
void main()
{
int a = 3, b = 3;
if (a > 5) //外层if语句
if (a < 10)a++; //内嵌if语句
else a--;
if (b > 5) //外层if语句
{ if (b < 10)b++; /*内嵌if语句*/ }
else b--;
printf("a=%d,b=%d\n", a, b);
}
运行结果:
a=3,b=2
程序说明:
(1)本程序由于书写不规范,给阅读和分析带来了困难。C语法规定,在分支结构中,else总是与前面最近的不带else的if相结合。根据这个原则,程序中的第一个else应该与if(a<10)配对,作为一个完整的if-else语句内嵌在外层if(a>5)中。第二个else应该与if(b>5)配对,原因是语句"if(b<10) b++;"在用一对花括号括起来之后,已作为if(b>5)的子句内嵌在其中。
(2)为了增强程序的可读性,应将本程序中内嵌if语句往右缩进几个格。
上面的例题都是在if子句中内嵌if语句,当内嵌层数较多时,else与if的配对关系往往不好确定,如果在else子句中内嵌if语句,配对关系比较明确。下面举例说明,请读者比较。
【例 3.10】编写求下面分段函数值的程序,其中x的值从键盘输入。
【解】当x小于0时,通过关系式“y=0”计算函数值,否则(则x>=0),还垚判断x是否小于10,若满足,说明x在[0,10)之内,因此用关系式y=x^3+5计算函数值,若不满足(即x>=10),则在判断x是否小于20,以此类推,在每次的判断中只要满足条件,就选对应的关系式计算,不满足时继续判断。所以本程序属于else子句包含另一个if语句的情况,应采用嵌套的if语句,其程序如下:
#include<stdio.h>
void main()
{
double x = 0, y = 0;
printf("Input data:");
scanf("%lf", &x);
if (x < 0) y = 0;
else
if (x < 10) y = x * x * x + 5;
else
if (x < 20)y = 2 * x * x - x - 6;
else
if (x < 30)y = x * x + 1;
else y = x + 3;
printf("x=% lf,y=%lf\n", x, y);
}
调试本程序时,应至少验证具有代表性的5个数据,例如,当输入0、5、15、25、35时,相应的函数值应分别为5.000000、130.000000、429.000000、626.000000、38.000000。
程序说明:
(1)程序中if语句只在else子句中不断包含另外if语句,其好处是if与else的配对关系一目了然,不容易出错。因此,建议读者尽量使用else子句中包含if语句的形式。
本例中的if语句常用下面的简单形式表示:
if (x < 0) y = 0;
else if (x < 10) y = x * x * x + 5;
else if (x < 20)y = 2 * x * x - x - 6;
else if (x < 30)y = x * x + 1;
else y = x + 3;
(2)程序中第一个else隐含了x>=0,所以在其后if的判断表达式中不必写成“x>=0&&x<10”,后面if的情况也相同。
3.6.1节中将更详细地介绍嵌套if语句。
3.4 switch语句
前面介绍的if语句只有两个分支,如果要用if语句解决多分支问题,只能使用嵌套if语句,如果分支很多,则嵌套层次多,编程时容易出错,阅读程序也会混淆。用switch语句可以方便地解决多分支问题。
【例 3.11】switch语句的示例。从键盘输入一个整数放在a中,当输入的值为1时,屏幕上显示A,输入2时显示B,输入3时显示C,输入其他整数时显示D。
【解】程序如下:
#include<stdio.h>
void main()
{
int a = 0;
scanf("%d", &a);
switch (a) //根据a的值选择分支
{
case 1: printf("A\n"); break; //a的值为1时
case 2: printf("B\n"); break; //a的值为2时
case 3: printf("C\n"); break; //a的值为3时
default: printf("D\n"); break; //a的值为1、2、3以外的数时
}
}
运行结果:
3
C
程序说明:
(1)switch、case和default都是关键字,不能作为标识符。
(2)当a的值为1或2或3时,执行相应case后面的语句,遇到break语句,立即结束switch语句的执行。如果a的1值为1、2、3以外的整数,则执行default后面的语句。
switch语句的一般形式为:
switch (表达式)
{
case 常量表达式1: 语句组1 break;
case 常量表达式2: 语句组2 break;
...
case 常量表达式n: 语句组n break;
default: 语句组n+1 break;
}
说明:
(1)switch后面的表达式和常量表达式k(=1,2,...,n)可以是整型或字符型。
(2)case后面不能出现变量或含变量的表达式,只能出现常量表达式,而且每个常量表达式的值不能相等。
(3)switch语句的执行过程是先用表达式的值逐个与常量表达式的值比较,在找到值相等的常量表达式时,执行其后的语句组,否则执行default后面的语句组。在执行case或default后面的语句组时,遇到break语句,则退出switch语句体,否则继续执行其下面的语句。例如:
#include<stdio.h>
void main()
{
int a = 0;
scanf("%d", &a);
switch (a)
{
case 1: printf("A\n");
case 2: printf("B\n");
case 3: printf("C\n"); break;
default: printf("D\n");
}
}
执行上面程序段时分别输入1、2、3、4,则程序运行结果分别是:
1 2 3 4
A B C D
B C
C
(4)在switch语句体中可以没有default分支,这时如果找不到对应的case分支,那么流程将不进入switch语句。例3.11的流程图参见图3.6。
图3.6 switch语句的执行过程
switch语句常用于处理键盘命令 。
在解决实际问题时,经常希望将某一限定范围作为case后的常量表达式,这是应先将该范围转成整数或字符,然后再通过switch语句进行处理,请看例3.12。
【例 3.12】输入一个百分制成绩,输出成绩等级A、B、C、D、E。输入的数据在90~100分为A,80~89分为B,70~79分为C,60~69分为D,0~59分为E,否则显示出错误信息。
【解】编程点拨:
本程序属于多分支问题,因此用switch语句解决,但因为要将每个分数段作为一个分支处理,所以必须把分数段转换成某一分支。可以用表达式“成绩/10”进行转换,例如,对于80~89之间的成绩,通过“成绩/10”的计算值都是8,即将一个分数段转化为一个整数。用10除是因为分数段的间隔是10。程序如下:
#include<stdio.h>
void main()
{
int score = 0, temp = 0;
printf("Input score:");
scanf("%d", &score);
if (score < 0 || score>100)
printf("Error!\n");
else
{
temp = score / 10; //把范围转换成整数
switch (temp)
{
case 10: //可以没有语句组
case 9:printf("A\n"); break;
case 8:printf("B\n"); break;
case 7:printf("C\n"); break;
case 6:printf("D\n"); break;
default:printf("E\n"); break;
}
}
}
第一次运行结果:
Input score:89
B
第二次运行结果:
Input score:105
Error!
其他情况请读者自行尝试。
程序说明:
(1)本程序在else子句中包含了switch语句,这在C语言中是允许的。
(2)case后面可以没有语句组。如在本程序中case10和case9的情况,都需要执行相同的语句组,这时case10后面的语句组可以省略。
(3)希望读者利用本例题中的程序,体会程序的书写格式。
switch语句的进一步讨论参见3.6.1节。
传送门🚪来喽~
传送门-上一节:C语言程序设计-关系运算符和关系表达式、逻辑运算符和逻辑表达式
传送门-下一节:C语言程序设计-if语句和switch语句的进阶、条件运算符和表达式
A good medicine tasks bitter.