第四章 逻辑运算和判断选取控制


§4.1 关系运算 §4.2 逻辑运算
§4.3 if语句 §4.4 switch语句
§4.5 程序举例  

 

§4.1 关系运算

关系运算:比较运算,用“关系表达式”进行运算。例、a > 3是一个关系表达式,它取两个值:"真"(true)和"假"(false)。

4.1.1 关系运算符及其优先次序

C语言有六种关系运算符:

< 小于 优先级相同(高)
<= 小于或等于
> 大于
>= 大于或等于
==(连续两个=) 等于 优先级相同(低)
!= 不等于

关系运算符与算术运算符、赋值运算符的优先级关系

例、

c>a+b 等效于c>(a+b)
a>b!=c 等效于(a>b)!=c
a==b<c 等效于a==(b<c)
a=b>c 等效于a=(b>c)

4.1.2 关系表达式

关系表达式:用关系运算符连接的表达式。

关系表达式的值:在各种语言中略有不同。

 
C 1(任意非0值也作为真) 0
PASCAL、FORTRAN True(1) False(0)

例、a=3, b=2, c=1, 则:

   a>b      真,表达式的值为1
   (a>b) = = c  真,表达式的值为1
   b+c<a     假,表达式的值为0

   d = a>b    d的值等于1
   f = a>b>c   f的值等于0

 


§4.2 逻辑运算

4.2.1 逻辑运算符及其优先次序

&& 逻辑“与”(AND)

“双目运算符”:要求两个操作数,

如:(a>b) && (x>y)

|| 逻辑“或”(OR)
! 逻辑“非”(NOT)

单目运算符,要求一个操作数,

如:!(a>b)

例、

a && b (若a和b均为真,逻辑表达式a&&b为真)

a || b (若a或b为真,逻辑表达式a||b为真)

!a (若a为真,逻辑表达式!a为假)

逻辑运算的“真值表”(操作数的值为不同组合时,逻辑表达式的值)

a b !a !b a && b a || b

在一个逻辑表达式中,包含多个逻辑运算符,如、

!a && b || x>y && c

按如图优先级运算:

例、

(a>b) && (x>y) 可以写为:a>b&&x>y

(a==b)||(x==y) 可以写为:a==b||x==y

(!a)||(a>b) 可以写为:!a||a>b

4.2.2 逻辑表达式

C语言
计算逻辑表达式的值 1 0
判断量的真假 非0 0

例、

① a=4 !a=0(假)

② a=4,b=5 a&&b=1(真)

③ a=4,b=5 a||b=1(真)

④ a=4,b=5 !a||b=1(真)

⑤ 4&&0||2 1

编译器在求解逻辑表达式的值时,采用“非完全求解”的方法,即:当求得表达式为真后,就结束求解;只有在需要执行下一个逻辑运算时,才继续运算。例如:

1、a && b && c

只有a为真时,才判别b的值;只有a和b均为真时,才判别c的值。

只要a为假,就不再判别b和c的值,直接求得表达式的值为假。

2、a || b || c

只要a为真,就不再判别b和c的值,直接求得表达式的值为真。

只有a为假时,才判别b的值;只有a和b均为假时,才判别c的值。

 


§4.3 if语句

if语句:判别条件是否满足(表达式的值为真时满足),来决定程序的流程(执行两路操作之一)。

4.3.1 if语句的三种形式

1、if (表达式) 语句

例如:

if (x>y) printf("%d",x);

2、if (表达式) 语句1 else 语句2

例如:

if (x>y) printf("%d",x);

else printf("%d",y);

3、

if (表达式1) 语句1

else if (表达式2) 语句2

else if (表达式3) 语句3

.....

else if (表达式m) 语句m

else 语句n

例如:

if (number > 500) const = 0.15;
else if (number > 300) const = 0.10;
else if (number > 100) const = 0.075;
else if (number > 50) const = 0.05;
else   const = 0;

说明:

1、if (表达式)中的“表达式”为逻辑表达式或关系表达式,例、

if (a==b && x==y) printf("a=b,x=y");

也可以为数值类型,如、

if (3) printf("O.K.");

if ('a') printf("%d", 'a');

2、注意语句应以分号结束。例、

if (x>0)

printf(" %f", x)

else

printf(" %f", -x)

3、语句可以是复合语句,例、

if (a+b>c && b+c>a && c+a>b)
{  
  s = 0.5*(a+b+c); area = sqrt(s*(s-a)*(s-b)*(s-c));
  printf("area=%6.2f",area);
}  
else  
  printf("it is not a trilateral");

注意:大括号{ }本身是一个完整的复合语句,不需要分号。

[例4.1] 输入两个实数,按代数值由小到大输出这两个数。

main()
{  
  float a,b,t;
  scanf("%f,%f",&a,&b);
  if (a>b)
  { t = a; a = b; b = t;
  }  
  printf("%5.2f,%5.2f",a,b);;
}    

运行示例、

3.6 ,-3.2↙
-3.2, 3.6

[例4.2] 输入三个数,按由大到小输出。

main()
{  
  float a,b,c,t;
  scanf("%f,%f,%f",&a,&b,&c);
  if (a>b)
    {t = a; a = b; b = t;}
  if (a>c)
    {t = a; a = c; c = t;}
  if (b>c)
    {t = b; b = c; c = t;}
  printf("%5.2f,%5.2f,%5.2f",a,b,c);
}  

4.3.2 if语句的嵌套 : if语句中包含另一个if语句。

一般形式:

if ( )    
  if ( ) 语句1 内嵌if
  else 语句2
else    
  if ( ) 语句3 内嵌if
  else 语句4

使用嵌套if语句时,必须特别注意if与else配对。配对原则:

从最内层开始,else总是与它上面最接近的(未曾配对的)if配对。

避免if与else配对错位的最佳办法是加大括号,同时,为了便于阅读,使用适当的缩进,(只有大括号能保证if和else不错位配对,缩进仅便于阅读)例、

if ()
 if ()  语句1
else
 if () 语句2
 else  语句3

if ()

加{}改变配对关系 if ()
if () 语句1

{if () 语句1}

else else
语句2

语句2

[例4.3] 有一函数如下,编一程序,输入一个x值,输出y值。

程序1:

main()
{ int x,y;
  scanf("%d",&x);
  if (x<0)    y = -1;
  else if (x==0) y = 0;
  else      y = 1;
  printf("x=%d,y=%d\n",x,y);
}  

程序2:

if (x>=0)
  if (x>0) y = 1;
  else y = 0;
else y = -1;

程序3:

y = -1;
if (x != 0)
  if (x>0) y = 1;
else y = 0;

程序4:

y = 0;
if (x >= 0)
  if (x>0) y = 1;
else y = -1;

4.3.3 条件运算符

在if语句中,在“表达式”为“真”和“假”时,都只执行一个赋值语句给同一个变量赋值,例如、

if (a>b) max = a;

else   max = b;

可以用如下条件运算符来处理:

max = (a>b) ? a : b;

其中,“(a>b) ? a : b”是一个条件表达式,若条件(a>b)成立,则条件表达式取值a;否则,取值b。

条件运算符要求有三个操作对象,称为“三目运算符”(它是C语言中唯一的一个三目运算符)。条件表达式的一般形式:

表达式1?表达式2:表达式3

说明:

1、条件运算符的执行顺序:先求解表达式1的值,若其为真,则求解表达式2的值,且整个条件表达式的值等于表达式2;若表达式1为假,则求解表达式3的值, 且整个条件表达式的值等于表达式3。

max = (a>b)?a:b 把条件表达式的值赋给max。

2、条件运算符的优先级高于赋值运算符,低于算术运算符和关系运算符。

max = (a>b)?a:b   max = a>b?a:b
a>b?a:b+1  

(a>b)?a:(b+1)

3、条件运算符的结合方向是“从右至左”。

a>b?a:c>d?c:d   (a>b)?a:(c>d?c:d)

4、只有在if语句的if分支、else分支均为赋值语句时,才可以用条件表达式代替。

if (a>b) printf("%d",a);

else printf("%d",b);

(a>b)?printf("%d",a):printf("%d",b)
     
    printf("%d",a>b?a:b);

5、表达式1、表达式2、表达式3的类型可以不同。

 

[例4.4] 输入一个字符。判别它是否大写字母,如果时,将其转换为小写,否则不转换。然后输出最后得到的字符。

main()
{ char ch;
  scanf("%c",&ch);
  ch = (ch >= 'A' && ch <= 'Z')?(ch+32):ch;
  printf("%c",ch);
}  

 


§4.4 switch语句

if语句处理两个分支,处理多个分支时需使用if-else if-else结构,而switch语句直接处理多个分支(当然包括两个分支)。其一般形式:

switch(表达式)
{ case 常量表达式1:语句1
  case 常量表达式2:语句2
 
  case 常量表达式n:语句n
  default:语句n+1
}  

意义:

当“表达式”=“常量表达式1”时,从“语句1”开始执行;
当“表达式”=“常量表达式2”时,从“语句2”开始执行;
 
当“表达式”=其它值时,从“语句n+1”开始执行;

例、根据考试成绩的等级(grade)打印出百分制分数段:

switch (grade)
{ case 'A':printf("85~100\n");
  case 'B':printf("70~84\n");
  case 'C':printf("60~69\n");
  case 'D':printf("<60\n");
  default: printf("error\n");
}  

当grade='A'时,程序从printf("85~100\n")开始执行,因此输出结果为:

85~100
70~84
60~69
<60
error

本例中,原意是输出一个值,要实现这一要求,应在语句后加break语句。

switch (grade)
{ case 'A':printf("85~100\n");break;
  case 'B':printf("70~84\n");break;
  case 'C':printf("60~69\n");break;
  case 'D':printf("<60\n");break;
  default: printf("error\n");
}  

break语句使程序跳出switch结构,使本例达到下图的要求:

注意:

1、当每一个case语句后均有break语句时,case出现的次序不影响执行结果。(default总是放在最后,这时,deafult后不需要break语句)。

2、case后面包含多个语录句时,不需要加大括号。(从....开始执行).

3、多个case可以共用一组执行语句,例、

case 'A':
case 'B':
case 'C': printf(">60\n"); break;

在A、B、C三种情况下,均执行相同的语句组。


§4.5 程序举例

[例4.5] 写程序,判某一年是否闰年。

闰年算法(教材p51):满足下列二者之一,是闰年。

① 能被4整除,但不能被100整除。
② 能被4整除,且能被400整除。

实现算法的框图:(N-S图,教材p60, 用leap=1表示闰年)

程序:

main()
{  
  int year,leap;
  scanf("%d",&year);
  if (year % 4 == 0)
    { if (year%100 == 0)
       { if (year %400 == 0)
             leap = 1;
        else leap = 0;
        }
     else leap = 1;
     }
  else leap = 0;
  if (leap)
     printf("%d is",year);
  else
     printf("%d is not",year);
  printf("a leap year\n");
}  
可以用一个逻辑表达式包括所有的闰年条件:

if ((year%4==0 && (year%100 != 0)) || (year%400==0 )) leap = 1;

else leap = 0;

[例4.6] 求方程的解:

算法:有以下几种可能性:

① a = 0,不是二次方程。
= 0,有两个相等实根。
> 0,有两个不等实根。
< 0, 有两个共轭复根。

N-S流程图:

程序:(disc=

#include "math.h"
main()
{ float a,b,c,disc,x1,x2,realpart,imagpart;
  scanf("%f,%f,%f",&a,&b,&c);/* 方程系数 */
  printf("The equation ");
  if (fabs(a) <= 1E-6) /* 判 a = 0 */
     { printf("is not quadratic\n"); exit(0); }
  else
     disc = b*b - 4*a*c; /* △ */
  if (fabs(disc) <= 1E-6) /* △=0 */
      printf("has two equal root: %8.4f",-b/(2*a));
  else if (disc > 1E-6) /* △>0 */
    { x1 = (-b + sqrt(disc))/(2*a);
      x2 = (-b - sqrt(disc))/(2*a);
      printf("has distinct real roots:%8.4f and %8.4f\n",x1,x2);
     }
  else /* △ < 0 */
    { realpart = -b/(2*a);
       imagpart = sqrt(-disc)/(2*a);
       printf("has complex roots:\n");
       printf("%8.4f+%8.4fi\n",realpart,imagpart);
       printf("%8.4f-%8.4fi\n",realpart,imagpart);
    }
}  

注意:

1、一个“好”的程序,必须考虑到各种可能的情况,均能作出正确处理。

2、判别一个实数是否为零(如本例中disc),正确的方法是判其绝对值小于一个很小的常数,如:

if (fabs(disc) <= 1E-6) ....

因为,实数在运算和存储中,不可避免地有误差,不能使用下述方法:

if (disc == 0.0) ....

[例4.7] 运输公司对客户计算运费。根据距离(s)给出一定折扣。折扣标准如下:

s<250km 没有折扣
250≤s<500 2%折扣
500≤s<1000 5%折扣
1000≤s<2000 8%折扣
2000≤s<3000 10%折扣
3000≤s 15%折扣

设每公里每吨货物的基本运价为p(price),货物重w(weight)吨,距离s,折扣率d(discount),则总运费f(freight)为:

f = p*w*s*(1-d)

算法分析:

折扣率的变化点均为250的倍数,用新变量c表示距离的范围:

s<250 c = 0
250≤s<500 c = 1
500≤s<750 c = 2
.....  
3000≤s c = 12

程序:

main()
{  
  int c,s;
  float p,w,d,f;
  scanf("%f,%f,%f",&p,&w,&s);/* 输入基本运价,重量,距离 */
  if (s >= 3000) c = 12;
  else c = s / 250;
  switch(c)
   {
    case 0: d = 0.0; break;
    case 1: d = 2.0; break;
    case 2:
    case 3: d = 5.0; break;
    case 4:
    case 5:
    case 6:
    case 7: d = 8.0; break;
    case 8:
    case 9:
    case 10:
    case 11: d = 10.0; break;
    case 12: d = 15; break;
   }
  f = p*w*s(1-d/100.0);
  printf("freight = %15.5f", f);
}  

 

 


本章要求及作业

要求:

1、关系运算、逻辑运算,各种运算符的优先级。

2、if语句、switch语句的概念及应用。