- 流程控制
- 分支语句(if和switch)
某一个区间:if
if语句
if(表达式){
语句;
}
其中:
if :关键字,告知编译系统这是一个条件判断语句。
表达式:表示对一个条件的判断,逻辑表达式。返回值只能是true,false。
语句 :当表达式的值为真时执行的语句。if语句的执行过程:
5.2.1.2 if…else语句
对一个条件的判断通常有两个可能:‘真(1)’或‘假(0)’,单分支结构只考虑了其条件为‘真’的情况并给出相应的操作,而没有考虑当条件为‘假’时程序应执行什么动作。当无论条件为‘真’还是为‘假’都需要执行不同的操作时,可以采用双分支选择结构。
C语言是通过if…else语句实现的。if…else…语句可以在条件为‘真’或为‘假’时执行指定的不同的动作。
if…else语句的执行过程:
if (表达式) 语句序列1;
else 语句序列2;
其中:
if、else:C语言的关键字,由if引导条件为‘真’是执行的操作;由else引导条件为‘假’是执行的操作。
语句序列:当表达式的值为真(或为假)时执行的语句。可以是一条语句或一组语句,如果是一组语句,需要采用复合语句形式,用{ }将这组语句括起来。
执行过程:
当表达式结果为真时,执行语句S1,放弃语句S2的执行,执行if语句的下一条语句;当表达式结果为假时,执行语句S2,放弃语句S1的执行,执行if语句的下一条语句。无论如何,对于一次条件判断,语句S1和语句S2只能有一个被执行。不能同时被执行。
例如:对及格和不及格学生的成绩信息都要输出。
if(grade>=60)
printf("\n%d,passed\n",grade);
else
printf("\n%d,failed\n",grade);
例5-6 输入整数a,b若大于100,则输出百位以上的数字,否则输出两数之和。
分支选择处理的条件是:>100.根据两个整数相除仍然为整数的原则,用()/100
main()
{
int a,b,y;
printf("enter a,b:");
scanf("%d%d",&a,&b);
if(a*a+b*b)>100 /* if(>100) */
y=(a*a+b*b)/100;
else
y=a+b;
printf("y=%d\n",y);
}
程序运行结果:
enter a,b:5 8
y=13
enter a,b:10 2
y=1
通常情况下,单分支结构也可以写成双分支结构的形式。因为双分支结构形式是一种对称形式,它更符合人们的思维习惯。写出来的程序也比较明确、清晰、易读。
例5-3题可改写为:
main()
{
int a,absa;
printf("enter one number: ");
scanf("%d",&a);
if(a<0)
absa=-a;
else
absa=a;
printf("|%d|=%d",a,absa);
}提示:在if…else…结构中,if体和else体中的语句都应该采用“右缩进“的格式书写。整个程序的缩进距离应该是一致的。使得程序清晰、易读。不遵循统一的缩进格式会使程序难以阅读。
在C语言中,除了采用if…else…语句可以实现双分支结构外,还可以通过条件表达式实现双分支结构。
C语言提供的条件表达式的格式:
表达式1?表达式2:表达式3
执行过程:
求解表达式1的值,若该值为‘真(非0)’:则将表达式2的计算结果值作为整个表达式的结果;否则将表达式3的计算结果值作为整个表达式的结果。
例如:if(a<0) absa=-a;
else absa=a; 可以由(a<0)?-a:a;替换。
例5-3题可改写为:
main()
{
int a,absa;
printf("enter one number: ");
scanf("%d",&a);
absa=(a<0)?-a:a;
printf("|%d|=%d",a,absa);
}
使用条件表达式实现双分支结构的条件是:(1)可以由一个if语句实现的双分支结构;(2)无论条件的结果是‘真’或是‘假’,所执行的只能是一条简单的语句,并且这条语句只能是给同一个变量赋值的赋值语句。
用条件表达式来代替if语句实现双分支结构,可以使程序变得简洁,提高执行速度。
将一个if…else…结构转换成条件表达式的方法如下:
(1)将原if语句的条件表达式写成e1;
(2)将当条件为真时的执行的赋值语句右端的表达式做e2;
(3)将当条件为假时的执行的赋值语句右端的表达式做e3;
5.2.1.3 if…else… if…语句
实际的程序设计中常常面对更多的选择,当一个问题不仅有两种可能的结果,需要从多方面进行判断,有多种可能的情况进行处理时,可以将if…else…语句扩展成为if…else…if…结构。
一般格式:
if(表达式1) 语句S1;
else if (表达式2) 语句S2;
else if(表达式e3) 语句S3;
…
else 语句Sn;
执行过程:
首先计算表达式1结果值,如果为真,执行语句S1,否则,计算表达式2的结果值,如果为真,执行语句S2,否则,计算表达式3的结果值,如果为真,执行语句S3,…,以此类推,直至计算表达式n,如果为真,执行语句Sn,否则,如果有语句Sn+1,则执行语句Sn+1,如果没有语句Sn+1,则执行if…else…if…语句的下一条语句。无论如何,对于一次条件判断,语句S1、S2、…、Sn和Sn+1只能选择一个被执行。不能同时被执行。
需要指出的:这是一条语句,属于双分支语句的扩充。
例5-7 从键盘上输入某个学生某门课程的成绩。当成绩高于90分时,输出A;成绩在80~89之间,输出B;成绩在70~79之间,输出C;成绩在60~69之间,输出D;而成绩不及格(小于60分)时输出E。
要想将成绩按等级分类,就必须判断输入的课程成绩与对应的范围进行比较,检查其值是否大于等于90分,是:输出’A’,否:要继续判断其值是否在80~89之间,是:输出’B’,否:判断其值是否在70~79之间,是:输出’C’,否:判断其值是否在60~69之间,是:输出’D’,否:说明成绩低于60分,则输出’E’。
程序清单如下:
main( )
{
int ave;
printf("Enter students scores in three tests:\n");
scanf("%d",& ave);
/*将成绩分类*/
printf("\n The student grade is: ");
/*下面使用if…else if..语句 */
if (ave >= 90) printf("A");
else if (ave >= 80) printf("B");
else if (ave >= 70) printf("C");
else if (ave >= 60) printf("D");
else printf("E");
/*这是一条语句*/
}
如果变量ave的值大于等于90,前4个条件均成立,但是由于第一个表达式的限定,只在执行了第一个printf语句之后就跳出了if…else if…结构。
对应于题中的if…else if..的语句格式,也可以采用if语句处理:
if (ave >= 90) printf("A");
if (ave >= 80&&ave <= 89) printf("B");
if (ave >= 70&&ave <= 79) printf("C");
if (ave >= 60&&ave <= 69) printf("D");
if (ave <60) printf("E");
然而,这里使用了5条if语句,由此看出,使用 if…else if…格式可以提高程序的效率,使程序少做许多逻辑判断。
例5-8 编写一个程序根据用户输入的三角形的三边判定三角形的类型(等边、等腰、直角、一般)并求其面积。
确定组成三角形的条件,任意两边之和大于第三边(包括三种情况);如果可以构成三角形,计算该三角形的面积,并继续判定是哪类三角形,这些三角形包括:等边三角形(三边相等)、等腰三角形(任意两边相等、三种情况)、直角三角形(两边平方之和等于第三边平方、三种情况)、一般三角形;如果不能构成三角形,则提示相应信息。程序清单如下:
#include "stdio.h"
#include "math.h"
main()
{
/*定义变量*/
float a,b,c;
float s,area;
/*输入三角形的三边*/
printf("a,b,c=");
scanf("%f,%f,%f",&a,&b,&c);
/*判定可否组成三角形*/
if(a+b>c&&a+c>b&&b+c>a)
{ /*计算并输出三角形面积*/
s=(a+b+c)/2.0;
area=sqrt(s*(s-a)*(s-b)*(s-c));
printf("area=%f\n",area);
/*判定三角形的类型*/
if(a==b&&b==c)
printf("等边三角形\n");
else if (a==b||b==c||a==c)
printf("等腰三角形\n");
else if (a*a+b*b==c*c||a*a+c*c=b*b||b*b+c*c=a*a)
printf("直角三角形\n");
else
printf("一般三角形\n");
}
else
printf("不能组成三角形\n");
}
例5-9 编程计算分段函数的值。
由于C语言不允许使用上标和根式,所以x2、x3应写成x*x、x*x*x的形式,根式由C语言提供的数学函数库中的sqrt函数实现,sqrt函数和sin函数原型定义在<math.h>头文件中。
程序流程如下所示:
程序清单如下:
#include "math.h"
main()
{
float x,y;
printf("enter a x:");
scanf("%f",&x);
if(x<1.0)
y=x*x+2*x+sin(x);
else if(x<10.0)
y=2*x-1;
else
y=sqrt(3*x*x*x-11);
printf("x=%f,Y=%f",x,y);
}
程序运行结果:
enter a x:1
x=1.000000,Y=1.000000
enter a x:10
x=10.000000,Y=54.671749
enter a x:0.5
x=0.500000,Y=1.729426由该题可以看出:当x取不同的值,会使y得到不同的结果。用if语句实现多分支结构,由于分支多、容易使程序冗长不清晰、可读性降低。使用C语言提供的switch开关语句专门处理多分支结构,可以简化程序的结构。
例5-7中对学生成绩分类处理的语句(左下方)也可以写成如右下方的形式。
这种if 语句中又包含一个或多个if语句的形式,称为if语句的嵌套。嵌套即可以出现在if语句块中,也可以出现在else中语句块中,一般形式如下:
在C语言中,对于多重嵌套if,最容易出现就是if与 else的配对错误,嵌套中的if与else的配对关系非常重要。C语言规定其原则为:从最内层开始,else总是与他上面相邻最近的不带else的if配对。如果if和else的数目不统一,可以加{}明确配对关系。
例如:if (x>1)
if (x>10) y=1;
else y=2;/*容易引起二义性的书写格式*/
虽然将else写在与第一个if同一层次上,企图使得两者相配对,但是由于else与第2个if相邻最近,实际上else是与第2个if配对,也即:在1<=x<=10之间y=2;改进的办法是使用复合语句形式,将上述程序段该为:
if (x>1)
{if (x>10) y=1;}
else y=2;
这里通过{ }限定了if语句的动作范围,使得else与第1个if配对,此时,当x<=1时y=2; x>10时y=1;提示 :在C语言中,不以书写格式区分不同的语句,语句之间是通过其逻辑关系加以区分的。因此,在if语句(包括三种格式)使用花括号“{ }”将同一层次的语句部分括起来,使得程序结构清楚、可读性强。特别是对较大型的程序更加必要。当仅有一条语句时,“{ }”可以省略。
通常情况下,在书写嵌套格式时采用“向右缩进”的形式。以保证嵌套的层次结构分明,可读性强。
例5-10 判断输入的字符是字母、数字或是其他字符。
首先可以通过getchar()函数实现,或通过scanf(“%c”,&ch);函数实现字符的输入,然后根据输入字符的ASCII码值判断它属于英文字母('a'-'z'、'A'-'Z')、数字('0'-'9')或其他字符。
程序清单如下:
#include "stdio.h"
main()
{
char c;
printf("Enter a single character:");
c=getchar();
if ((c>='a'&&c<='z')||(c>='A'&&c<='Z'))
printf("it's an alphabetic character\n");
else
{
if(c>='0'&&c<='9')
printf("it's a digit\n");
else
printf("it's other character\n");
}
}
程序运行结果:
Enter a single character:a
it's an alphabetic character
Enter a single character:9
it's a digit
Enter a single character:\
it's other character
例5-7中对学生成绩分类处理的语句(左下方)也可以写成如右下方的形式。
这种if 语句中又包含一个或多个if语句的形式,称为if语句的嵌套。嵌套即可以出现在if语句块中,也可以出现在else中语句块中,一般形式如下:
在C语言中,对于多重嵌套if,最容易出现就是if与 else的配对错误,嵌套中的if与else的配对关系非常重要。C语言规定其原则为:从最内层开始,else总是与他上面相邻最近的不带else的if配对。如果if和else的数目不统一,可以加{}明确配对关系。
例如:if (x>1)
if (x>10) y=1;
else y=2;/*容易引起二义性的书写格式*/
虽然将else写在与第一个if同一层次上,企图使得两者相配对,但是由于else与第2个if相邻最近,实际上else是与第2个if配对,也即:在1<=x<=10之间y=2;改进的办法是使用复合语句形式,将上述程序段该为:
if (x>1)
{if (x>10) y=1;}
else y=2;
这里通过{ }限定了if语句的动作范围,使得else与第1个if配对,此时,当x<=1时y=2; x>10时y=1;提示 :在C语言中,不以书写格式区分不同的语句,语句之间是通过其逻辑关系加以区分的。因此,在if语句(包括三种格式)使用花括号“{ }”将同一层次的语句部分括起来,使得程序结构清楚、可读性强。特别是对较大型的程序更加必要。当仅有一条语句时,“{ }”可以省略。
通常情况下,在书写嵌套格式时采用“向右缩进”的形式。以保证嵌套的层次结构分明,可读性强。
例5-10 判断输入的字符是字母、数字或是其他字符。
首先可以通过getchar()函数实现,或通过scanf(“%c”,&ch);函数实现字符的输入,然后根据输入字符的ASCII码值判断它属于英文字母('a'-'z'、'A'-'Z')、数字('0'-'9')或其他字符。
程序清单如下:
#include "stdio.h"
main()
{
char c;
printf("Enter a single character:");
c=getchar();
if ((c>='a'&&c<='z')||(c>='A'&&c<='Z'))
printf("it's an alphabetic character\n");
else
{
if(c>='0'&&c<='9')
printf("it's a digit\n");
else
printf("it's other character\n");
}
}
程序运行结果:
Enter a single character:a
it's an alphabetic character
Enter a single character:9
it's a digit
Enter a single character:\
it's other character
switch语句
采用if…else if…语句格式实现多分支结构,实际上是将问题细化成多个层次,并对每个层次使用单、双分支结构的嵌套,采用这种方法一旦嵌套层次过多,将会造成编程、阅读、调试的困难。当某种算法要用某个变量或表达式单独测试每一个可能的整数值常量,然后作出相应的动作。可以通过C语言提供的switch语句直接处理多分支选择结构。
一般格式:
switch (表达式)
{
case 常量标号1:语句序列1;
break;
case 常量标号2:语句序列2;
break;
…
case 常量标号n:语句序列n;
break;
default: 语句S;
}
其中:
①表达式:可以控制程序的执行过程,表达式的结果必须是整数、字符或枚举量值。
②case后面的常量标号,其类型应与表达式的数据类型相同。表示根据表达式计算的结果,可能在case的标号中找到,标号不允许重复,具有唯一性,所以,只能选中一个case标号。尽管标号的顺序可以任意的,但从可读性角度而言,标号应按顺序排列。
③语句序列是switch语句的执行部分。针对不同的case标号,语句序列的执行内容是不同的,每个语句序列允许有一条语句或多条语句组成,但是case中的多条语句不需要按照复合语句的方式处理(用{}将语句括起来),若某一语句序列i为空,则对应的break语句可以省略(去掉)。
④break是中断跳转语句,表示在完成相应的case标号规定的操作之后,不继续执行switch语句的剩余部分而直接跳出switch语句之外,继而执行switch结构后面的第一条语句,如果不在switch结构的case中使用break语句。程序就会接着执行下面的语句。
⑤default用于处理所有switch结构的非法操作。当表达式的值与任何一个case都不匹配时,则执行default语句。提示:尽管可以省略default语句,但是提供一条default语句可以对那些不满足条件的情况加以说明,从而防止有些条件被忽略测试。
执行过程:
从流程图中可以看出:每一个case可以拥有一个或多个动作,每一个case的结束处都有一个break语句,这条语句可以使控制流程立即退出switch结构。
switch语句的执行过程:
①计算表达式的值。
②将表达式的值依次与每一个case后的常量标号进行比较。如果与某个case标号相等,则执行该case标号后的语句;如果在所有语句执行之后有break语句,则立即退出switch结构,标志整个switch多分支选择结构处理结束。假设没有break语句,将无条件的执行下一条case语句(这时,不需要对下一个case标号进行检查比较,也许是该语句后面的所有case 语句)。
③如果表达式的值与所有的case标号比较后没有找到与之匹配的标号,则做如下处理:若有default语句则在执行default语句后的语句后结束多分支结构。若没有default语句,则不执行switch语句的任何语句,直接结束switch语句的执行。
例4-11 编写一个程序,完成两个数的四则运算(数与运算符由键盘给入)。
#include <stdio.h>
main ()
{
float x,y;
char op;
printf("\ntype in your expression:");
scanf("%f%c%f",&x,&op,&y);
switch(op)
{
case '+':printf("%6.2f%c%6.2f=%6.2f\n",x,op,y,x+y);
break;
case '-':printf("%6.2f%c%6.2f=%6.2f\n",x,op,y,x-y);
break;
case '*':printf("%6.2f%c%6.2f=%6.2f\n",x,op,y,x*y);
break;
case '/':if(y==0) printf("error!\n");
else printf("%6.2f%c%6.2f=%6.2f\n",x,op,y,x/y);
break;
default: printf("expression error!");
}
getch();
}
程序运行结果:
type in your expression:5+6
5.00+6.00=11.00
如果在一个case中不写break语句,程序将顺序执行switch结构的下一条语句,例如:
int select=1;
switch(select)
{
case 1: “c program.\n”;
case 2: “basic program.\n”
break;
}
当select的值为1时,程序的结果是:
c program.
basic program.
case 1不是以break语句结束的,程序不再进行标号的判断直接执行了下一条语句。
那么是否最后一个case中的语句就可以省略break语句了?例如:
int select=2;
switch(select)
{ case 1: “c program.\n”;
break;
case 2: “basic program.\n”
}
当select的值为2时,程序的结果是:
basic program.
因为case 2在整个switch结构的最后,即使不使用break语句,也执行到程序的结束。但是,假如现在需要修改以下程序,例如:
int select=2;
switch(select)
{ case 1: “c program.\n”;
break;
case 2: “basic program.\n”;
case 3: “pascal program.\n”;
break;
}
当select的值为2时,程序的结果是:
basic program.
pascal program.
出现错误的原因在于,case 2已经不是最后一条语句了。因此,除非特殊要求,否则应该对每一个分支(包括default语句)都加上break语句,以使流程能够结束switch结构。提示:需要在switch结构的case中使用break语句而忘记使用的话,将会导致程序结果的错误。
利用switch语句case中break语句的特点,可以实现多个case共用一组执行语句。 当switch结构的多个case标号需要执行相同的语句,则可以采用下面的格式:
switch (i)
{case 1:
case 2:
case 3:语句1;break;
case 4:
case 5: 语句2;break;
}
当整型变量i的值为1、2或3时,执行语句1;当整型变量i的值为4、5时执行语句2;将几个标号列在一起,意味着这些条件具有一组相同的动作。
例4-12 输入一个月份,输出2003年该月有多少天。
要判断输入的月份有多少天,就要知道该月是大是小,对于每一年而言,大月(1、3、5、7、8、10、12)有31天,小月(4、6、9、11)有30天。由于2003年不是闰年,所以2月份为28天。程序清单如下:
#include <stdio.h>
main( )
{ int month;
int day;
printf("please input the month number: ");
scanf("%d",&month);
switch (month)
{
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12: day=31; break:
case 4:
case 6:
case 9:
case 11:day=30;break;
case 2:day=28;break;
default: day=-1:
}
if (day= =-1)printf("invalid month input!\n");
else printf("2003.%d has %d days\n",month,day);
}
这里引用了标记值-1,表示输入月份出错的情况。对标记值必须有所选择,使它能够区别要接受的正常的数据。因为每月的天数应该是非负整数,所以本例中可以采用负值-1作为标记值。
例4-13 编写一个程序,对于输入一个给定的百分数成绩,输出用相应的“A”, “B”, “C”, “D”, “E”表示的等级成绩。
这个问题前面采用if…else…语句结构实现的,这里则采用switch语句结构实现。
main()
{int score,num,flag;
char grade;
flag=1;
scanf(“%d”,&score)
if (score == 100)
num=9;
else
num=(score-score%10)/10;
switch(num)
{ case 9:grade=‘A’ ;break;
case 8:grade=‘B’ ;break;
case 7:grade=‘C’ ;break;
case 6:grade=‘D’ ;break;
case 5:
case 4:
case 3:
case 2:
case 1:grade=‘E’ ;break;
default: break;
}
printf(“the score is:%d,the grade is %c.\n” ,
score,grade);
}
程序运行结果:
87
the score is:87,the grade is B.
使用switch语句要注意以下几点:
(1)表达式必须是()括起来,不能为空。(2)switch语句中的变量以及case后的常量表达式都必须是整型或字符型。(3)在使用switch语句时只能对等式进行测试。(4)switch语句中的所有case后的常量表达式的值都必须互不相同。(4)每个case和default后可以有多个语句组成,并且可以包括条件分支语句和循环语句。(5)标号后的“:”不能省略 ,语句后的“;”分号也不能省略。(6)由于在执行一个case语句之后,控制将自动转移到语句后的下一个语句,因此在一个case结束,下一个case开始之前,用一个break语句退出switch语句是必要的。
什么时候用switch语句比用if语句更好?
switch语句与if语句不同, switch语句只能对整型(字符型、枚举型)等式进行测试,而if 语句可以处理任意数据类型的关系表达式、逻辑表达式以及其它表达式。
如果有两条以上基于同一个整型变量的条件表达式,那么最好使用switch语句 。例如:与其使用下述的if语句格式:
if(value==1)
result+=2;
else if(value==2)
result-=2;
elseif(value ==3)
result*=2;
else
result/=2;
不如使用如下switch代码,它更易于阅读和维护:
switch(value)
{
case 1:result+=2;
break;
case 2:result-=2;
break;
case 3:result*=2three.\n”);
break;
default:result/=2;
}提示:使用switch语句的前提条件是条件表达式必须是基于同一个整型(或字符型)变量。实型和字符串都是不允许的。
- 循环语句(while,do while,for和foreach)
- 控制循环结构(break,continue,return)
- 标准输入输出
- 什么是控制台
- 读取控制台输入
break语句
格式:break; 或 break 标号;
功能:带标号的break语句从多重循环体的内部跳出到标号所标志的那层循环,并从标号标志的那层循环后面的语句继续执行。
例3.22 带标号的break语句的使用。
outer:
for (int i = 0 ; i < 5 ; i++ ){
for (int j = 0; j < 3 ; j++ ){
。。。
if (j == 1){
//跳出outer标签所标识的循环。
break outer;
}
}
}
continue语句
格式:continue; 或 continue 标号;
功能:带标号的continue语句可从多重循环的内层循环跳到外层循环,执行标号所标识的循环的下一轮。
例3.24 带标号的continue语句的使用。
outer:
for (int i = 0 ; i < 3 ; i++ ){
for (int j = 0; j < 3 ; j++ ){
。。。
if (j == 1){
continue outer;
}
}}
return语句
return关键字并不是专门用于跳出循环的,而是结束一个方法。一旦在循环体内执行到一个return语句,该方法将会结束,循环自然也随之结束。
例3.25 使用return结束循环。
for (int i = 0; i < 3 ; i++ ){
System.out.println("i的值是" + i);
if (i == 1){
return;
}
System.out.println(“return后的输出语句");
}用户在程序运行过程中从外界传递数据到程序中(此为输入数据),并将处理结果传递到程序外部,如显示到屏幕上或写出到文件中(此为输出数据)。
什么是控制台
“控制台”(Console)就是由操作系统提供的一个字符界面窗口,用于实现系统与用户的交互——接收用户输入的数据并显示输出结果。
在控制台中运行的程序被称为控制台应用程序 ,也称字符界面应用程序。
读取控制台输入
java.util.Scanner类的功能并不仅限于控制台输入数据的读取,它的对象还可以关联到字符串、文件或其他的数据源。
构造方法 public Scanner(InputStream source) 例如,Scanner sc=new Scanner(System.in);
public Sting next() 读取下一个单词,以空格符或换行符作为分隔单词的标记。例如,String name=sc.next();
public int nextInt() 读取一个整数,如果输入的下一个单词不能解析为有效的整数(例如包含汉字等非数值字符),则出错。
public double nextDouble() 读取一个双精度浮点数,如果输入的下一个单词不能解析为有效的浮点数,则出错。
public Boolean nextBoolean() 读取一个布尔值,如果输入的下一个单词不能解析为有效的boolean值(true或false),则出错。
例3.26 Scanner类的使用。
import语句:导入java.util包中定义的Scanner类。
String name = s.nextLine(); int age = s.nextInt();
double salary = s.nextDouble();