值得注意的是,C语言在求解逻辑表达式的值时,采用“非完全求解”的方法。
即:
当求出某个逻辑运算符的左边的运算量的值就能够明确地确定这个逻辑运算的结果时,就可以提前结束求解过程,直接给出运算结果。
例如:
(1)a&&b&&c
若a的值为“假”,就不用再判别b和c的值,直接给出整个表达式的值为“假”;若a的值为“真”,b的值为“假”,则a&&b的值为“假”,就不用再判别c的值,直接给出整个表达式的值为“假”。
只有当a的值为“真”时,才需要判别b的值;只有当a&&b的值为“真”时,才需要判别c的值。
如:
a=0;b=1;c=1;
d=a&&b&&(c=b+3)
运算结果是:
d的值为0,c的值仍为1。
(2)a||b||c
若a的值为“真”,就不用再判别b和c的值,直接给出整个表达式的值为“真”;若a的值为“假”,b的值为“真”,则a||b的值为“真”,也可以直接给出整个表达式的值为“真”;只有a和b的值均为“假”时,才需要判别c的值。
如:
a=1;b=0;c=0;
d=a||b||(c=b+3)
运算结果是:
d的值为1,c的值仍为0。
4.2if语句
if语句可以根据给定的条件进行判断,决定执行某个分支程序段,以实现选择结构的程序设计。
4.2.1if语句的三种形式
C语言的if语句有3种形式:
单分支if语句、双分支if语句和多分支if语句。
1.单分支if语句
单分支if语句的形式为:
if(表达式)语句
执行单分支选择语句时,首先判断表达式的值,若为非0(即判定为逻辑“真”),则执行表达式后面的语句;若为0(即判定为逻辑“假”),则不执行表达式后面的语句。
控制流程如图4.1所示。
图4.1单分支选择结构
说明:
(1)if语句中的“表达式”一般为关系表达式或逻辑表达式,也可以是任何数据类型的表达式,以其值的非0或0来确定逻辑真假。
(2)if(表达式)后面的语句可以是一条语句,也可以是由多个语句组合而成的复合语句。
例如:
if(a
例4.1输入一个数,如果该数大于等于0,则输出它的平方根,当它小于0,则不做任何处理。
#include
main()
{
doublex;
scanf(“%f”,&x);
if(x>=0)
printf(“%10.6f\n”,sqrt(x));/*sqrt为开平方的库函数*/
}
2.双分支if语句
双分支if语句的形式为:
if(表达式)
语句1
else
图4.2双分支选择结构
语句2
当表达式的值为非0时,执行语句1;当表达式的值为0时,执行语句2。
控制流程如图4.2所示。
注意:
else是if语句的一部分,必须与if配套,不能单独使用。
例4.2输入任意三个整数n1、n2、n3,求三个数中的最大值。
程序如下:
main()
{
intn1,n2,n3,max;
printf("Pleaseinputthreenumbers:
");
scanf("%d,%d,%d",&n1,&n2,&n3);
if(n1>n2)
max=n1;
else
max=n2;
if(n3>max)
max=n3;
printf("max=%d\n",max);
}
程序运行结果为:
Pleaseinputthreenumbers:
11,22,18↙
max=22
本例中的第1个if语句,可优化为如下不带else的形式:
max=n1;if(n2>max)max=n2;
这种优化形式的基本思想是:
首先取一个数预置为max(最大值),然后再用max依次与其余的数逐个比较,如果发现有比max大的,就用它给max重新赋值,比较完所有的数后,max中的数就是最大值。
这种方法,对从3个或3个以上的数中找最大值的处理,非常有效。
请读者仔细体会。
例4.3输入三个整数,分别放在变量a、b、c中,程序把输入的数据重新按由小到大的顺序放在变量a、b、c中,最后输出a、b、c中的值。
程序如下:
main()
{
inta,b,c,t;
printf(“inputa,b,c:
”);
scanf(“%d%d%d”,&a,&b,&c);
printf(“a=%d,b=%d,c=%d\n”,a,b,c);
if(a>b)
{t=a;a=b;b=t;}
if(a>c)
{t=a;a=c;c=t;}/*至此三个数中最小的数已放入a中*/
if(b>c)
{t=b;b=c;c=t;}
printf(“a=%d,b=%d,c=%d\n”,a,b,c);
}
程序运行结果为:
inputa,b,c:
623424↙
a=62,b=34,c=24
a=24,b=34,c=62
3.多分支if语句
多分支if语句的形式为:
if(表达式1)语句1
elseif(表达式2)语句2
elseif(表达式3)语句3
图4.3多分支if语句的流程图
...
elseif(表达式n)语句n
else语句n+1
执行多分支if语句时,如果表达式i的值为非0,则执行语句i,后面的语句不再执行;否则执行else后面的语句。
流程图如图4.3所示
例4.4编写程序,根据输入的学生成绩,给出相应的等级。
90分以上的等级为A,60分以下的等级为E,其余每10分为一个等级。
程序如下:
main()
{
intg;
printf(“Enterg:
”);
scanf(“%d”,&g);
printf(“g=%d:
”,g);
if(g>=90)printf(“A\n”);
elseif(g>=80)printf(“B\n”);
elseif(g>=70)printf(“C\n”);
elseif(g>=60)printf(“D\n”);
elseprintf(“E\n”);
}
程序运行结果为:
Enterg:
78↙
g=78:
C
4.2.2if语句的嵌套
在上述3种if语句结构中,当if(表达式)或else后面语句本身又是一个if语句结构时,就形成了if语句的嵌套结构。
if语句的二层嵌套结构如下:
if()
if()语句1
else
语句2
else
if()语句3
else语句4
在if语句的嵌套结构中并不需要对称,只根据需要决定嵌套的形式。
在写if语句的嵌套结构时,要注意else与if配对的规则,else总是与在它前面的、离它最近的、尚未与其它else匹配的if相配对。
如:
if(表达式1)
if(表达式2)语句1
else语句2
则else与第二个if相配对。
如果想与else与第一个if配对,则必须采用下面的形式:
if(表达式1)
{if(表达式2)语句1}
else语句2
即用花括号把内层if语句括起来后,使得此内层if语句在语法上成为一条独立的语句,从而使得else只能与外层的if配对。
例4.5编写一程序实现符号函数的功能。
程序如下:
符号函数为:
main()
{
intx,y;
printf(“Enterx:
”);
scanf(“%d”,&x);
y=-1;
if(x!
=0)
{if(x>0)y=1;}
else
y=0;
printf(“x=%d,y=%d\n”,x,y);
}
程序运行结果为:
Enterx:
-8↙
x=-8,y=-1
该题也可以用更加简明的程序来实现,本例程序只是为了说明在if语句中又嵌套不含else的if语句的使用方法。
4.3条件运算符和条件表达式
C语言提供了一个特殊的运算符——条件运算符,条件运算符由两个符号组成,它们是问号“?
”和冒号“:
”。
它是C语言提供的惟一的三目运算符,即要求有三个运算对象。
由它构成的条件表达式可以形成简单的选择结构,这种选择结构能以表达式的形式内嵌在允许出现表达式的地方。
条件表达式的一般形式为:
表达式1?
表达式2:
表达式3
条件表达式的求解过程:
先求“表达式1”的值,当“表达式1”的值为非零时,求出“表达式2”的值,并以“表达式2”的值作为整个条件表达式的值;当“表达式1"的值为零时,求出“表达式3”的值,并以“表达式3”的值作为整个条件表达式的值。
若“表达式2”与“表达式3”的数据类型不一致,则遵循算术运算的类型转换规则,即取二者中较高的类型。
如:
x>0?
5:
1.5的结果为实型数5.0或1.5。
说明:
(1)条件运算符的优先级高于赋值运算,但低于逻辑运算、关系运算和算术运算。
如:
a>b?
a:
b+1相当于(a>b)?
a:
(b+1)
(2)条件运算符具有自右向左的结合性。
如:
max=a>(b>c?
b:
c)?
a:
b>c?
b:
c相当于:
max=a>(b>c?
b:
c)?
a:
(b>c?
b:
c)
4.4switch语句
switch语句是C语言提供的一个多分支选择语句。
在C语言中多分支选择结构也可以用多分支if语句或if语句的嵌套来实现,但有时使用switch语句可以使程序的结构显得更加清晰。
4.4.1switch语句的一般形式与执行过程
switch语句的一般形式为:
switch(表达式)
{
case常量表达式1:
语句1
case常量表达式2:
语句2
…
case常量表达式n:
语句n
[default:
语句n+1]
}
说明:
(1)紧跟在switch后的“表达式”只能是整型、字符型或枚举型表达式,且表达式两边的一对括号不能省略。
(2)关键字case与跟在其后的常量表达式合称为case语句标号。
在关键字case和常量表达式之间一定要有空格,例如case10:
不能写成casel0:
。
各常量表达式的类型必须与swicth后的表达式的类型相同,并且各常量表达式的值还应该互不相同。
(3)关键字default也是起语句标号的作用,代表所有case语句标号之外的语句标号。
default标号一般出现在所有的case标号之后,但它也可以出现在某个case标号之前,并且不会改变程序对其中的某个分支的选择顺序。
在switch语句体中也可以没有default。
(4)各case语句标号后的语句可以是一条语句,也可以是多条语句,并且可以不必用{}括起来;必要时,case语句标号后的语句还可以省略。
执行swicth语句时,首先计算紧跟在switch关键字后的表达式的值,当表达式的值与某一个case后面的常量表达式的值相等时,就执行该标号后开始的各语句,包括在其后的所有case和default中的语句,直到switch语句体结束。
如果没有与该值相等的常量表达式,并且存在default标号,则从default标号后的语句开始执行,直到switch语句体结束;如果没有default标号,则跳过switch语句体,什么也不做。
例4.6编写程序,输入能代表一个日期的三个整数(年:
y、月:
m、日:
d),计算并输出该日是该年的第几天。
程序如下:
main()
{
inty,m,d,dd=0;
printf("Enteryyyy/mm/dd:
");
scanf("%d/%d/%d",&y,&m,&d);
printf("%d/%d/%d",y,m,d);
switch(m-1)
{
case11:
dd=dd+30;
case10:
dd=dd+31;
case9:
dd=dd+30;
case8:
dd=dd+31;
case7:
dd=dd+31;
case6:
dd=dd+30;
case5:
dd=dd+31;
case4:
dd=dd+30;
case3:
dd=dd+31;
case2:
dd=dd+28;
case1:
dd=dd+31;
case0:
dd=dd+d;
}
if((m>2)&&(y%4==0&&y%100!
=0||y%400==0))
dd=dd+1;/*闰年的2月有29天*/
printf("%d\n",dd);
}
程序运行结果为:
Enteryyyy/mm/dd:
2007/4/18↙
2007/4/18108
例4.7用switch语句改写例4.4。
原题是根据输入的学生成绩,输出对应的等级。
程序如下:
main()
{
intg;
printf("Enteramark:
");
scanf("%d",&g);
printf("g=%d:
",g);
switch(g/10)
{
case10:
case9:
printf("A\n");
case8:
printf("B\n");
case7:
printf("C\n");
case6:
printf("D\n");
default:
printf("E\n");
}
}
程序运行结果为:
Enteramark:
78↙
g=78:
C
D
E
程序在输出了与78分相关的等级C之后,紧接着又输出了与78分毫不相关的等级D、E,这显然不符合题意。
为了改变这种情况,switch语句常常需要与break语句配合使用。
4.4.2switch语句体中的break语句
switch语句通常总是和break语句联合使用,使得switch语句真正起到多分支结构的作用。
使用方法是在每个case之后的语句的最后加上一个break语句,break语句的功能是强制地跳出switch语句体。
例如可用break语句修改例4.7的程序,使之能达到原题意的要求。
main()
{
intg;
printf("Enteramark:
");
scanf("%d",&g);
printf("g=%d:
",g);
switch(g/10)
{
case10:
case9:
printf("A\n");break;
case8:
printf("B\n");break;
case7:
printf("C\n");break;
case6:
printf("D\n");break;
default:
printf("E\n");
}
}
程序运行结果为:
Enteramark:
85↙
g=85:
B
4.5选择结构程序举例
例4.8写一程序,从键盘上输入一个年号year(4位十进制整数),判断该年是否闰年。
判断某年是否为闰年的条件是:
年号能被4整除但不能被100整除,即图4.4中位于大圆内、中圆外的所有年号;或者年号能被400整除,即图4.4中位于小圆内的所有年号。
程序如下:
main()
{
intyear,leap;/*变量leap用来作为某年是否为闰年的标志:
0代表不是;1代表是*/
printf("Pleaseinputtheyear:
");
/4
所有年号
scanf("%d",&year);
if(year%4==0)
/100
if(year%100!
=0)
/400
leap=1;
else
if(year%400==0)
leap=1;
else
图4.4闰年的条件
leap=0;
else
leap=0;
if(leap==1)
printf("%disaleapyear.\n",year);
else
printf("%disnotaleapyear.\n",year);
}
利用逻辑运算能够描述复杂条件的特点,可以将上述程序优化如下:
main()
{
intyear,leap;
printf("Pleaseinputtheyear:
");
scanf("%d",&year);
leap=0;
if(year%4==0&&year%100!
=0)
leap=1;
if(year%400==0)
leap=1;
if(leap)
printf("%disaleapyear.\n",year);
else
printf("%disnotaleapyear.\n",year);
}
也可以把逻辑运算的结果直接赋值给一个变量,从而省略掉前面的if语句。
main()
{
intyear,leap;
printf("Pleaseinputtheyear:
");
scanf("%d",&year);
leap=(year%4==0&&year%100!
=0)||(year%400==0);
if(leap)
printf("%disaleapyear.\n",year);
else
printf("%disnotaleapyear.\n",year);
}
例4.9求一元二次方程的解:
分析:
随着方程中的变量a,b,c的变化,一元二次方程有以下几种可能性:
1.a=0,不是二次方程。
2.b*b-4*a*c=0,有两个相等实根。
3.b*b-4*a*c>0,有两个不相等的实根。
4.b*b-4*a*c<0,有两个共轭复根。
图4.5求解一元二次方程的程序流程图
程序流程如图4.5所示。
程序如下:
#include
main()
{
floata,b,c,disc,x1,x2,realpart,imagpart;
scanf("%f,%f,%f",&a,&b,&c);
printf("Thee