第五章 选择结构程序设计
5.1 关系运算符和关系表达式
5.1.1 关系运算符
-
在程序中需要比较两个量的大小,这样的运算符称为关系运算符;
-
在C语言中有6种关系运算符:6级运算符{<(小于) <=(小于等于) >(大于) >=(大于等于)}7级运算符{==(等于) !=(不等于)}
-
关系运算符均为双目运算符,结合性均为从左向右
-
运算结果为一个逻辑值,即:真或假;用1代表真,0代表假;判断用非0表示真,输出用1表示真
-
浮点数时用近似值表示的,当用“==”比较两个浮点数是否相等时,由于存在误差,可能会得到错误的结果
例如:
- 5>3 值为真,即输出1
- 5<=4 值为假,即输出0
- ‘5’==5 值为假,即输出0
- 5!=3 值为真,即输出1
- 5>4>3 运算符为两个>,同级结合性从左向右,5>4为真,输出1,1>3为假,输出0;故值为假,即输出0
5.1.2 关系表达式
- 关系表达式是用关系运算符将两个表达式连接起来进行关系运算的式子;
- 一般形式:表达式 关系运算符 表达式 (表达式可以为关系表达式,从而形成嵌套)
- 在关系表达式的计算中6个关系运算符的结合性从左到右,并且优先级低于算术运算符,均高于赋值运算符
- 当关系运算符两边运算对象类型不一致时,如一边是整型,一边是浮点型,系统自动把整型转为浮点型,然后进行比较
例如:
a+b>c/d 等价为(a+b)>(c/d) {运算符有+(4级) /(3级) >(6级);故先算/再算+最后算>}
'a'+1<c 等价为('a'+1)<c {运算符有+(4级) <(6级);故先算+再算<}
-i-5*j==k+1等价为(-i-5*j)==(k+1) {运算符有-(负号1级) -(4级) *(3级) ==(7级) +(4级);故先算-再算*再算—+再算==}
a>b==c 等价为(a>b)==c
x=a!=c==d 等价为x=((a!=c)==d)
例:计算关系表达式的值
#include <stdio.h>
void main()
{
char c='k';
int i=1,j=2,k=3;
float x=3e+5,y=0.85;
printf("%d,%d\n",'a'+5<c,-i-2*j>=k+1);
printf("%d,%d\n",1<j<5.6,x-5.25>i+j+k);
printf("%d,%d\n",i+j+k==-2*j,k==j==i+5);
}
输出:1,0
1,1
0,0
第一条printf语句:a对应的ASCCI码值为97,k对应ASCII码值为107,97+5=102,102<107,故'a'+5<c为真,输出1;-1-2*2=-5,k+1=4,-5<4,故-i-2*j>=k+1为假,输出0
第二条printf语句:1<2为真,输出1,1.0<5.6为真,输出1;x=3e+5=300000.000000,x-5.25>1+2+3,故x-5.25>i+j+k为真,输出1;
第三条printf语句:-2*j=-4,i+j+k=6,-4不等于6,故i+j+k==-2*j为假,输出0;i+5=6,k==j为假,输出0,0==6为假,故k==j==i+5为假,输出0
5.2 逻辑运算符和逻辑表达式
5.2.1 逻辑运算符
-
C语言有3种逻辑预算符:双目运算符:{&&(11级逻辑与) ||(12级逻辑或)从左向右} 单目运算符:!(2级逻辑非结合性从右向左)
- a&&b,若a,b为真,则a&&b为真
- a||b,若a,b之一为真,则a||b为真
- !a,若a为真,则!a为假
-
逻辑运算的结果也是一个逻辑值,1代表真,0代表假
5.2.2 逻辑表达式
- 逻辑表达式是用逻辑运算符将两个表达式连接起来的式子
- 一般形式:表达式 逻辑运算符 表达式
- 逻辑运算符优先级由高到低为:!(2级非)->&&(11级与)->||(12级或)
a>b && c>d等价为(a>b) && (c>d)
!b==c||d<a等价为((!b)==c)||(d<a)
a+b>c&&x+y<b等价为((a+b)>c)&&((x+y)<b)
a && b && c等价为(a && b) && c
!!!x等价为!(!(!x))
- 数学语言中用0.5<x<2.0来表示x的值在0.5和2.0之间的数,但在C语言中需要用x>0.5&&x<2.0来表示
- 对于&&和||逻辑运算符,如果根据左边的运算对象能判定表达式的结果,则右边的运算对象不被执行
- a && b;只有a为真时,才计算b
- a || b;只有a为假时,才计算b
例如:计算逻辑表达式的值
#include <stdio.h>
main()
{
char c='k';
int i=1,j=2,k=3;
float x=3e+5,y=0.85;
printf("%d,%d\n",!x*!y,!!!x);
printf("%d,%d\n",x||(i=5)&&j-3,i<j&&x<y);
printf("%d,%d\n",i==5&&c&&(j=8),x+y||i+j+k);
}
输出:0,0
1,0
0,1
第一个printf:!二级运算符,*三级运算符,!y为0,!x为0,0*0为0,故!x*!y为假,输出0;!!!x相当于!(!(!x)),!x为0,!(!x)为1,!(!(!x))为0,故!!!x为假,输出0
第二个printf:||为12级运算符,()为1级运算符,&&为11级运算符,-为4级运算符,j-3为-1,x||(i=5)为真,输出1,1&&-1,-1不为0,故1&&-1为真,输出1;i<j为真,x<y为假,故(i<j)&&(x<y)为假,输出为0
第三个printf:==7级运算符,&&11级运算符,()1级运算符,i==5为假,输出0,0&&c为假,输出0,0&&8为假,输出0,故i==5&&c&&(j=8)为假,输出0;+为4级运算符,||为12级运算符,x+y为真输出1,则不再看右侧运算对象,x+y||i+j+k为真,输出1
5.3 if语句及其构成的选择结构
5.3.1 if语句的形式
5.3.1.1 单分支if语句
- 一般形式:if(表达式)
语句序列;(if字句)
后继语句;
- if表达式与语句序列(if子句)算一条语句,if就近控制一条语句
- if后表达式结构为真进入if字句,为假则直接执行后继语句
例如:输入一个数,正数则求其平方根输出,否则输出该数
#include <stdio.h>
void main()
{
float x,y;
printf("输入一个数:");
scanf("%f",&x);
y=x;
if(x>0)
y=sqrt(x); /*sqrt()为求正数平方根函数*/
printf("%f",y);
}
运行情况:
输入一个数:4
y=2.000000
5.3.1.2 双分支if语句
-
一般形式:if(表达式)
语句序列1;(if字句)
else
语句序列2;(else字句)
后继语句;
-
若if后表达式的值为真,执行if字句;否则执行else子句
-
有else必须有if,有n个else就至少有n个if
-
if和else都只就近控制1条语句;整个if else算1条语句
-
语句序列1和语句序列2可以为复合语句{},复合语句算1条语句
例如:输入一个数,正数则求其平方根输出,否则输出该数
#include <stdio.h>
void main()
{
float x,y;
printf("输入一个数");
scanf("%f",&x);
if(x>0)
y=sqrt(x);
else
y=x;
printf("y=%f",y);
}
5.3.1.3 注意事项
-
if后的表达式通常是逻辑表达式和关系表达式,也可以是其他表达式;如算数表达式或赋值表达式,也可以是一个常量或变量
-
if(a = 5)语句;表达式a = 5的值永为非0,其后的语句总要执行,虽不定出现,但合法
-
if(b)语句;
-
if(a=b) printf("%d",a); else printf("a=0"); 含义:把b赋给a,如为非0,则输出该值,否则输出a=0
-
-
在if语句的两种形式中,if子句和else子句均为单条语句,若需执行一组语句,须把这组语句加上花括号{}组成一条复合语句,在}后无需加分号
例:输入3个数a,b,c,要求按由小到大顺序输出
#include <stdio.h>
void main()
{
float a,b,c,temp;
scanf("%f%f%f",&a,&b,&c);
if(a>b)
{
temp=a;
a=b;
b=temp;
}
if(a>c)
{
temp=a;
a=c;
c=temp;
}
if(b>C)
{
temp=b;
b=c;
c=temp;
}
printf("%5.2f,%5.2f,%5.2f\n",a,b,c);
}
运行情况:
5.3 4.6 8.2
4.60, 5.30, 8.20
5.3.2 if语句的嵌套
- if语句的嵌套一般格式:
if(表达式1)
if(表达式2) 语句1;
else 语句2;
else
if(表达式3) 语句3;
else 语句4;
-
else与if之间的配对关系:C语言规定else总是与它上面最近的if语句配对。
-
使用if语句的嵌套结构实现多分支时,采用规范形式:
if(表达式1)
语句1;
else if(表达式2)
语句2;
else if(表达式3)
语句3;
else if(表达式4)
语句4;
。。。
else if(表达式n)
语句n;
else
语句n+1;
语义:当表达式i(1<=i<n)为真时,执行语句i,然后跳出整个if语句执行后继语句;否则判断else后面表达式i+1是否为真。若所有表达式均为假,则执行语句n+1,然后执行后继语句。
例:利用输入字符的ASCII值判断字符类型:控制字符的ASCII值为小于32;数字字符’0‘‘9’的ASCII值为4857;大写字母’A‘’Z‘的ASCII值为6590;小写字母’a’’z‘的ASCII值为97122,其余则为其他字符。
#include <stdio.h>
void main()
{
char c;
printf("输入一个字符");
c=getchar();
if(c<32)
printf("c为控制字符\n");
else if(c>=48 && c<=57)
printf("c为数字字符\n");
else if(c>=65 && c<=90)
printf("c为大写字母\n");
else if(c>=97 && c<=122)
printf("c为小写字母\n");
else
printf("c为其他字符\n");
}
5.3.3 条件运算符和条件表达式
-
若在if语句中只执行单个赋值语句,可使用条件表达式来实现
-
条件运算符为”?“和”:“,是C语言中唯一一个三目运算符,要求有三个运算对象
-
条件表达式一般形式:表达式1 ? 表达式2 : 表达式3 求值规律为若表达式1值为真,则以表达式2的值作为整个表达式的值,否则以表达式3的值作为整个表达式的值
-
if(a>b) 相当于:max=((a>b)?a:b);
max=a;
else
max=b;
-
条件运算符的优先级低于关系运算符和算术运算符,但高于赋值运算符。故max=((a>b)?a:b);可去掉括号写为max=a>b?a:b;
-
条件运算符?和:是一对运算符,不能分开单独使用
-
条件运算符结合性从右向左;a>b?a:c>d?c:d应理解为a>b?a:(c>d?c:d)
-
在条件表达式中,表达式1的类型可以与表达式2和表达式3的类型不同,且表达式2与表达式3的类型也可不同,此时条件表达式的值的类型为二者较高的类型
5.4 switch语句及其构成的选择结构
5.4.1 switch语句的形式
switch语句是一种用于实现多分支选择结构的语句,其特点是可以根据一个表达式的多种值选择多个分支,又称之为开关语句
-
switch语句的一般形式为:
-
switch(表达式) { case 常量表达式1: 语句块1 case 常量表达式2: 语句块2 ... case 常量表达式n: 语句块n default: 语句块n+1 }
-
-
执行switch语句时,首先计算switch后面表达式的值,然后自上而下逐个与case后的 常量表达式进行比较,相等的话则从该case后为入口,执行该常量表达式冒号后面的所有语句块,直到switch语句结束(default后的语句块也输出);当表达式的值与所有的case后的常量表达式均不相等时,若存在default,则执行default后面的语句块,若没有default,则结束switch语句。
-
关键字switch后面括号内的表达式可以为整型、字符型和枚举类型
-
switch后用花括号{}括起来的部分称为switch语句体
-
常量表达式由常量构成,不含变量和函数;关键字case与后面的常量表达式合称为case语句标号,且各常量表达式的值不能相同
-
在关键字case和常量表达式之间一定要有空格;case 10:不能写成case10:
-
各语句块可以是一条或多条语句,不必用{}括起来,也可以为空语句,甚至省略语句块
-
关键字default也起标号作用,代表所有case语句标号之外的标号
-
通常default写在最后
例:用1~7表示星期一到星期日,先输入数字,输出对应的星期几的英文单词
#include <stdio.h>
void main()
{
int a;
printf("input integer number:");
scanf("%d",&a);
switch(a)
{
case 1: printf("Monday\n");
case 2: printf("Tuesday\n");
case 3: printf("Wednesday\n");
case 4: printf("Thursdat\n");
case 5: printf("Friday\n");
case 6: printf("Saturday\n");
case 7: printf("Sunday\n");
default: printf("error\n");
}
}
运行情况:
5
Friday
Saturday
Sunday
error
case常量表达式只相当于一个语句标号,表达式的值和某常量表达式的相等,则转向该标号执行,但不能在在执行完自动跳出整个switch语句体,此种情况可采用C语言中break语句跳出switch语句体
5.4.2 在switch语句中使用break语句
break语句也称间断语句,可以在各语句中加上break语句。每当执行break语句时,即跳出switch语句体
例:修改上一个程序,增加break语句
#include <stdio.h>
void main()
{
int a;
printf("input integer number:");
scanf("%d",&a);
switch(a)
{
case 1: printf("Monday\n");break;
case 2: printf("Tuesday\n");break;
case 3: printf("Wednesday\n");break;
case 4: printf("Thursdat\n");break;
case 5: printf("Friday\n");break;
case 6: printf("Saturday\n");break;
case 7: printf("Sunday\n");break;
default: printf("error\n");
}
}
运行情况:
5
Friday
5.5 选择结构程序设计举例
5.5.1 输入一个年份,判断是否公历中的闰年;
能被4整除而不能被100整除或能被400整除的年份就是闰年
#include <stdio.h>
void main()
{
int year;
printf("input the year:");
scanf("%d",&year);
if(year%4==0&&year%100!=0||year%400==0)
printf("Yes");
else
printf("No");
}
或者
#include <stdio.h>
void main()
{
int year;
printf("input the year:");
scanf("%d",&year);
printf((year%4==0&&year%100!=0||year%400==0)?"Yes":"No");
}
或者
#include <stdio.h>
void main()
{
int year;
printf("input the year:");
scanf("%d",&year);
printf(year%(year%100?4:400)?"No":"Yes");
}
5.5.2 输入一个不多于4位的正整数,求出该数是几位数,并逆序打印出各位数字
一个数对10取余得到最低位数字;
#include <stdio.h>
void main()
{
int a,a1,a2,a3,a4;
printf("输入一个不多于4位的正整数:");
scanf("%d",&a);
a1=a%10;
a2=a/10%10;
a3=a/100%10;
a4=a/1000%10;
if(a4!=0)
printf("4:%d%d%d%d\n",a1,a2,a3,a4);
else if(a3!=0)
printf("3:%d%d%d\n",a1,a2,a3);
else if(a2!=0)
printf("2:%d%d\n",a1,a2);
else
printf("1:%d\n",a1);
}
5.5.3 公司员工的工资等于保底薪水加利润提成,已知员工的保底薪水位500,所接工程的利润profit(整数)与工资提成的关系:profit<=1000无提成;1000<profit<=2000提成10%;2000<profit<=5000提成15%;5000<profit<=10000提成20%;10000<profit提成25%
- 使用if语句嵌套
#include <stdio.h>
void main()
{
int a=500; /*定义底薪500*/
long profit; /*定义利润*/
float b; /*定义实际工资*/
printf("输入工程利润:");
scanf("%ld",&profit);
if(profit<=1000)
b=a;
else if(1000<profit&&profit<=2000)
b=a+profit*0.1;
else if(2000<profit&&profit<=5000)
b=a+profit*0.15;
else if(5000<profit&&profit<=10000)
b=a+profit*0.2;
esle
b=a+profit*0.25;
}
-
使用switch语句:将利润profit与提成的关系换成某些整数和提成的关系,可以发现提成的变化点都是1000的整数倍,将利润除1000
profit<=1000 对应0,1 提成0
1000<profit<=2000 对应1,2 提成10%
2000<profit<=5000 对应2,3,4,5 提成15%
5000<profit<=10000 对应5,6,7,8,9,10 提成20%
10000<profit 对应10,11。。。。 提成25%
解决两个区间重叠问题,可将利润先减1,再整除1000即可
profit<=1000 对应0 提成0
1000<profit<=2000 对应1, 提成10%
2000<profit<=5000 对应2,3,4 提成15%
5000<profit<=10000 对应5,6,7,8,9 提成20%
10000<profit 对应10,11。。。。 提成25%
#include <stdio.h>
void main()
{
float a=500;
long profit;
int symbol;
printf("输入利润:");
scanf("%ld",&profit);
symbol=(profit-1)/1000;
switch(symbol)
{
case 0: break;
case 1: a+=profit*0.1;break;
case 2:
case 3:
case 4: a+=profit*0.15;break;
case 5:
case 6:
case 7:
case 8:
case 9: a+=profit*0.2;break;
default: a+=profit*0.25;
}
printf("a=%.2f",a);
}
5.5.4 编写程序,输入一个整数,打印出它是奇数还是偶数
#include <stdio.h>
void main()
{
int a;
printf("输入一个整数:");
scanf("%d",&a);
if(a%2==0)
printf("a为偶数\n");
else
printf("a为奇数\n");
}
5.5.5 编写程序要求输入x的值,输出y的值(-5<x<0)y=x,(x=0)y=x-1,(0<x<10)y=x+1
#include <stdio.h>
void main()
{
float x,y;
printf("输入x的值:");
scanf("%f",&x);
if(-5<x&&x<0)
y=x;
else if(x==0)
y=x-1;
else if(0<x&&x<10)
y=x+1;
else
y=-5;
if(y!=-5)
printf("y=%.2f\n",y);
else
printf("error\n");
}
5.5.6 当a为正数时,将下面语句改为switch语句
if(a<30) m=1;
else if(a<40) m=2;
else if(a<50) m=3;
else if(a<60) m=4;
else m=5;
a的变化点转折是10的倍数,a<30对应3;a<40对于4,a<50对应5,a<60对应6
#include <stdio.h>
void main()
{
int c,a,m;
printf("输入一个数:");
scanf("%d",&a);
if(a<=0)
c=-1;
else
c=a/10;
switch(c)
{
case 0:
case 1:
case 2: m=1;break;
case 3: m=2;break;
case 4: m=3;break;
case 5: m=4;break;
default : m=5;
}
if(c!=-1)
printf("m=%d\n",m);
else
printf("error\n");
}
5.5.7 对货物征收税金,一万元以上的货收5%,5000以上、1万以下的收3%,1000以上、5000以下的收2%,1000元以下不收费,读入货物价格,输出税金
#include <stdio.h>
void main()
{
int a,b;
printf("输入货款:");
scanf("%d",&a);
if(a>=10000)
b=a*0.05;
else if(a>=5000)
b=a*0.03;
else if(a>=1000)
b=a*0.02;
else
b=a;
printf("税金=%d",b);
}
5.5.8 输入某个学生成绩,成绩在85以上,输出”VERY GOOD“;60到85之间输出”GOOD“,低于60,输出”BAD“
#include <stdio.h>
void main()
{
int grade;
printf("输入学生成绩:");
scanf("%d",&grade);
if(grade>=85)
printf("VERY GOOD\n");
else if(grade>=60)
printf("GOOD\n");
else
printf("BAD\n");
}
5.5.9 输入两个两位数正整数x、y,将这两个数合并成一个整数放在z中,合成方式:将x的十位和个位依次放在z的千位和十位上,y的十位和个为依次放在z的百位和个位上,若输出的不是两位正整数,给出提示
#include <stdio.h>
void main()
{
int x,y,z;
int x1,x2,y1,y2;
printf("输入两个整数:");
scanf("%d%d",&x,&y);
if(x<10||x>99||y<10||y>99)
printf("error");
x1=x/10;
x2=x%10;
y1=y/10;
y2=y%10;
z=x1*1000+y1*100+x2*10+y2;
printf("z=%d\n",z);
}
GOOD“,低于60,输出”BAD“
#include <stdio.h>
void main()
{
int grade;
printf("输入学生成绩:");
scanf("%d",&grade);
if(grade>=85)
printf("VERY GOOD\n");
else if(grade>=60)
printf("GOOD\n");
else
printf("BAD\n");
}
5.5.9 输入两个两位数正整数x、y,将这两个数合并成一个整数放在z中,合成方式:将x的十位和个位依次放在z的千位和十位上,y的十位和个为依次放在z的百位和个位上,若输出的不是两位正整数,给出提示
#include <stdio.h>
void main()
{
int x,y,z;
int x1,x2,y1,y2;
printf("输入两个整数:");
scanf("%d%d",&x,&y);
if(x<10||x>99||y<10||y>99)
printf("error");
x1=x/10;
x2=x%10;
y1=y/10;
y2=y%10;
z=x1*1000+y1*100+x2*10+y2;
printf("z=%d\n",z);
}