第二周:判断
2.1 比较
简单的判断语句:
if(条件成立){
//执行代码
}
条件
- 计算两个值之间的关系,所以叫做关系运算
关系运算的结果
- 当两个值的关系符合关系运算符的预期时,关系运算的结果为整数1,否则为整数0
- printf("%d ",5==3); -> 结果为0
- printf("%d ",5>3); -> 结果为1
- printf("%d ",5<=3); -> 结果为0
优先级
- 所有的关系运算符的优先级比算术运算低,但是比赋值运算的高
- 7 >= 3 + 4; 先计算
3 + 4
,再将结果和7比较,比较的结果为1 - int r = a > 0; 先计算 a > 0 , 再将比较的结果赋值给r
- 7 >= 3 + 4; 先计算
- 判断是否相等的
==
和!=
的优先级比其他的低,而连续的关系运算是从左到右进行的- 5 > 3 == 6 > 4 分别计算 5 > 3和 6 > 4 ,再判断他们的结果是否相等,也就是 1 == 1,最后的结果为1
- 6 > 5 > 4 先计算 6 > 5,再用结果和4进行比较,也就是 1 > 4,最后的结果为0
- a == b == 6 先计算 a == b ,再用结果和6进行比较,也就是(a == b)== 6
- a == b > 0 先计算 b > 0,再用结果和a进行比较,也就是 a == ( b > 0)
2.2 判断
注释
- 以两个斜杠
"//"
开头的语句为注释,为程序提供解释 ` - 注释插入在程序代码中,用来向读者提供解释信息。他们对于程序的功能没有任何影响,但是往往能使得程序更容易被理解。
"//"
是C99的注释,ANSI C不支持- 延续数行的注释,要用多行注释的格式来写。多行注释由一对字符序列“/*”开始,以“*/”结束。
- 多行注释也可以写在一行内
比较两个数的大小
用户输入两个数,用比较两个数的大小,输出较大的那个数。
程序流程图:
代码实现:
#include <stdio.h>
int main(int argc, char *argv[]) {
int a = 0;
int b = 0;
int max = 0;
printf("请输入两个整数:");
scanf("%d %d", &a, &b);
if(a>b){
max = a;
} else {//b>=a
max = b;
}
printf("大的那个是%d
", max);
}
运行结果:
请输入两个整数:5 10
大的那个是10
if语句的大括号的作用
- 当if语句后面跟着大括号时,程序会执行大括号里面的所有语句。
- 当if语句后面没有大括号时,程序只会执行紧跟
if
后的那条语句。 - 对于else也同样适用
嵌套的判断
- 当if的条件满足或者不满足的时候要执行的语句也可以是一条if或if-else语句,这就是嵌套的if语句
- if-else总是两个相邻最近的做匹配
例如:
if(条件A成立){
if(条件B成立){
//执行代码
} else {
//执行代码
}
}
tips
- 在if或else后面总是用{}
- 即使只有一条语句的时候
- 这样做的好处是代码清晰容易阅读
- 虽然这么做,我们写的代码会多一个大括号,但是对于程序运行效率来讲没有任何影响。
级联的if-else if
- 当我们要判断的条件有多个时,我们可以使用一个if,一个或多个else if 对这些条件进行连接。
- 当然在这个级联的判断块的最后我们可以跟一个else也可以用else if结尾,换句话说if、else-if、else的组合是灵活多变的,关键看你想怎么使用它。
示例:
if(条件1){
//执行块1
}
else if (条件2){
//执行块2
}
else if (条件3){
//执行块3
}
...
else { // 这个else可以省略掉
//执行块n
}
switch-case
- c语言还有一种判断-分支的语句可以在特殊的情况下代替级联的if-else-if,他就是switch-case
- 语法
switch (控制表达式){
case 常量:
语句;
语句;
break;
case 常量:
语句;
语句;
case 常量:
case 常量:
语句;
default:
语句;
break;
}
- 控制表达式只能是整数的结果
- 常量可以是常数,也可以是常数计算的表达式
- 程序会根据表达式的结果选择对应常量的case执行
- 程序遇到break;才会退出swtich-case语句块,换句话说如果触发了一个case语句,程序会一直执行到遇到break语句才会停止,期间可能穿过多个case前提是这些case中都没有break语句。
- switch-case相比if-else if的好处是可以使我们的程序更加直观。
swtich-case 示例-成绩转换
本题要求编写程序将一个百分制成绩转换为五分制成绩。转换规则:
- 大于等于90分为A
- 小于90且大于等于80分为B
- 小于80且大于等于70为C
- 小于70且大于等于60为D
- 小于60为E
输入格式:
输入在一行中给出1个整数的百分制成绩
输入出格式:
在一行中输出对应的五分制成绩
输入样例:
90
输出样例:
A
程序实现:
#include <stdio.h>
int main(int argc, char *argv[]) {
int score = 0;
printf("请输入你的分数(0-100):");
scanf("%d", &score);
if(score < 0 || score > 100) {
printf("输入的分数有误,请输入0至100以内的分数");
} else {
score = score / 10;
switch(score){
case 10:
case 9:
printf("A");
break;
case 8:
printf("B");
break;
case 7:
printf("C");
break;
case 6:
printf("D");
break;
default:
printf("E");
break;
}
}
return 0;
}
执行结果:
请输入你的分数(0-100):80
B
错题解析
以下语句是否可以通过编译:
int n = 0;
if ( 1<=n<=10 );
题目分析:
- 首先语句是可以通过编译的,1<=n<=10是一个正确的关系表达式,虽然它表示的并不是n在0到10([0,10])这个范围中。
- if语句后面没有如果没有执行语句,可以写一个分号结束,当然没有执行语句的if语句本身没有任何意义。
- 再来看
1 <= n <= 10
这个关系表达式的结果,关系表达式按优先级从左到右结合,1<=0的结果为0, 0<=10的结果为1,进一步分析,关系表达式的值只能为0或1,0小于1小于10,因此整个表达式的值总是为1.
2.3 课后习题
1、题目内容:
UTC 是世界协调时,BJT 是北京时间,UTC 时间相当于 BJT 减去 8。现在,你的程序要
读入一个整数,表示 BJT 的时和分。整数的个位和十位表示分,百位和千位表示小时。如
果小时小于 10,则没有千位部分;如果小时是 0,则没有百位部分;如果分小于 10 分,
需要保留十位上的 0。如 1124 表示 11 点 24 分,而 905 表示 9 点 5 分,36 表示 0
点 36 分,7 表示 0 点 7 分。
有效的输入范围是 0 到 2359,即你的程序不可能从测试服务器读到 0 到 2359 以外的输
入数据。
你的程序要输出这个时间对应的 UTC 时间,输出的格式和输入的相同,即输出一个整数,
表示 UTC 的时和分。整数的个位和十位表示分,百位和千位表示小时。如果小时小于 10,
则没有千位部分;如果小时是 0,则没有百位部分;如果分小于 10 分,需要保留十位上的
0。
提醒:要小心跨日的换算。
输入格式:
一个整数,表示 BJT 的时和分。整数的个位和十位表示分,百位和千位表示小时。如果小
时小于 10,则没有千位部分;如果小时是 0,则没有百位部分;如果分小于 10 分,需要
保留十位上的 0。
输出格式:
一个整数,表示 UTC 的时和分。整数的个位和十位表示分,百位和千位表示小时。如果小
时小于 10,则没有千位部分;如果小时是 0,则没有百位部分;如果分小于 10 分,需要
保留十位上的 0。
输入样例:
903
输出样例:
103
题目分析
- 用户输入一个四位数来表示小时和分钟,前两位表示小时,而后两位表示分钟。
- 我们使用24小时制来表示UTC和BJT实际因此小时的范围为0到23,而分钟的范围为0到59,因此我们需要分别校验用户输入的小时和分钟是否合法。
- 如果小时小于10千位为0,小时等于0百位也为0,如果分钟为零小时不为零则需要保留十位的零,如果小时为零,分钟的十位小于零,则无需保留前面的0,例如 7 表示 0点7分,换句话说除了个位数,如果高位以及高位以上的数如果为零则都可以省略掉
- 需要把用户输入的北京时间转换为世界协调时,我们知道UTC时间 = BJT时间 - 8 小时 ,而8小时在我们的程序中的表示为 800 ,因此转换的公式为:UTC时间 = 用户输入的BJT时间 - 800
- 由于BJT时间小于8小时的情况下就会有跨天的情况,因此方便考虑我们使用负数来表示,比如说-1600就代表UTC时间的前一天的16点也就是BJT时间的0点,我们知道当用户输入0点时依据我们上一条的公式计算的结果为-800,因此我们还需要做一个转换。
-(-800+2400)
= -1600,也就是说当UTC时间计算结果为负数时我们还需要用公式 UTC时间 = - ( UTC时间 + 2400 ) 来转换为用户查看的时间。 - 确认读懂需求并且对需求的实现有一个细致的分析后我们就可以开始用程序实现了
#include <stdio.h>
int main(int argc, char *argv[]) {
const int TIMELAG = 800; //北京时间和世界协调时间的时差
const int TIMEOFDAY = 2400; //一天的时间24制在程序中的表示
int bjtTime = 0;
int utcTime = 0;
/*时间有效性状态码,
0:有效
1:无效,小时超出0~23范围 ,
2:无效,分钟超出0~59范围
*/
int validCode = 0;
int hours = 0;
int minutes = 0;
printf("请输入北京时间,用一个四位正整数表示,"
"如1124表示11点24分,7表示0点7分:");
scanf("%d", &bjtTime);
//校验用户输入时间的正确性 Begin
if(validCode == 0) {
hours = bjtTime / 100;
if(hours < 0){
validCode = 1;
} else if(hours > 23){
validCode = 1;
}
}
if(validCode == 0) {
minutes = bjtTime % 100;
if(minutes < 0){
validCode = 2;
} else if(minutes > 59){
validCode = 2;
}
}
//校验用户输入时间的正确性 End
if(validCode == 0) {//有效则进行时间转换处理
utcTime = bjtTime - TIMELAG;
if(utcTime < 0) {
utcTime = -(utcTime + TIMEOFDAY);
printf("%d(负数代表UTC前一天的时间,比如-2300表示UTC时间前一天23点整)
", utcTime);
} else {
printf("%d
", utcTime);
}
} else if(validCode == 1) {
printf("输入的时间无效:小时超出范围,请输入0~23内的小时
");
} else if(validCode == 2) {
printf("输入的时间无效:分钟超出范围,请输入0~59内的分钟
");
} else {//当新增了错误码,但忘记新增else-if分支时提示,帮助排错。
printf("输入的时间无效:错误码%d,请联系管理员
",validCode);
}
return 0;
}
运行结果:
请输入北京时间,用一个四位正整数表示,如1124表示11点24分,7表示0点7分:1124
324
请输入北京时间,用一个四位正整数表示,如1124表示11点24分,7表示0点7分:7
-1607(负数代表UTC前一天的时间,比如-2300表示UTC时间前一天23点整)
请输入北京时间,用一个四位正整数表示,如1124表示11点24分,7表示0点7分:2400
输入的时间无效:小时超出范围,请输入0~23内的小时
请输入北京时间,用一个四位正整数表示,如1124表示11点24分,7表示0点7分:2360
输入的时间无效:分钟超出范围,请输入0~59内的分钟
2、题目内容:
无线电台的 RS 制信号报告是由三两个部分组成的:
R(Readability) 信号可辨度即清晰度.
S(Strength) 信号强度即大小.
其中 R 位于报告第一位,共分 5 级,用 1—5 数字表示.
1---Unreadable
2---Barely readable, occasional words distinguishable
3---Readable with considerable difficulty
4---Readable with practically no difficulty
5---Perfectly readable
报告第二位是 S,共分九个级别,用 1—9 中的一位数字表示
1---Faint signals, barely perceptible
2---Very weak signals
3---Weak signals
4---Fair signals
5---Fairly good signals
6---Good signals
7---Moderately strong signals
8---Strong signals
9---Extremely strong signals
现在,你的程序要读入一个信号报告的数字,然后输出对应的含义。
输入样例
59
输出样例
Extremely strong signals, perfectly readable.
题目分析
- 通过用户输入的数字告诉用户的含义
- 输入有效性校验数字必须是一个两位数
- 数字的十位代表可辨度,个位代表信号强度
- 通过分析我们可以知道程序用到的都是对固定值进行的判断,因此比较适合使用switch-case分支。
- 输出时信号强度在前面,可辨度在后面。
程序实现:
#include <stdio.h>
int main(int argc, char *argv[]) {
int rsCode = 0;
int sinals = 0; //信号强度
int redable = 0; //可辨度
int isValidRSCode = 1;
printf("请输入一个信号报告两位整数,十位代表可辨度,个位代表信号强度,
"
"比如59表示Extremely strong signals, perfectly readable. :");
scanf("%d", &rsCode);
//用户输入校验 Begin
if(rsCode <= 10){
isValidRSCode = 0;
}else if(rsCode > 100) {
isValidRSCode = 0;
}
//用户输入校验 End
if(isValidRSCode == 1){
sinals = rsCode % 10;
switch(sinals) {
case 1:
printf("Faint signals, barely perceptible");
break;
case 2:
printf("Very weak signals");
break;
case 3:
printf("Weak signals");
break;
case 4:
printf("Fair signals");
break;
case 5:
printf("Fairly good signals");
break;
case 6:
printf("Good signals");
break;
case 7:
printf("Moderately strong signals");
break;
case 8:
printf("Strong signals");
break;
case 9:
printf("Extremely strong signals");
break;
default:
printf("Error:Unown signals%d", sinals);
break;
}
printf(",");
redable = rsCode / 10;
switch(redable) {
case 1:
printf("Unreadable");
break;
case 2:
printf("Barely readable, occasional words distinguishable");
break;
case 3:
printf("Readable with considerable difficulty");
break;
case 4:
printf("Readable with practically no difficulty");
break;
case 5:
printf("Perfectly readable");
break;
default:
printf("Error:Unown readable%d", redable);
break;
}
printf(".
");
} else {
printf("信号必须是一个两位整数");
}
return 0;
}
执行结果:
请输入一个信号报告两位整数,十位代表可辨度,个位代表信号强度,
比如59表示Extremely strong signals, perfectly readable. :59
Extremely strong signals,Perfectly readable.
请输入一个信号报告两位整数,十位代表可辨度,个位代表信号强度,
比如59表示Extremely strong signals, perfectly readable. :11
Faint signals, barely perceptible,Unreadable.