本系列博客用于记录学习浙江大学翁恺老师的C语言程序设计,系列笔记链接如下:
C语言程序设计学习笔记:P1-程序设计与C语言
C语言程序设计学习笔记:P2-计算
C语言程序设计学习笔记:P3-判断
C语言程序设计学习笔记:P4-循环
C语言程序设计学习笔记:P5-循环控制
C语言程序设计学习笔记:P6-数据类型
C语言程序设计学习笔记:P7-函数
C语言程序设计学习笔记:P8-数组
C语言程序设计学习笔记:P9-指针
C语言程序设计学习笔记:P10-字符串
C语言程序设计学习笔记:P11-结构类型
C语言程序设计学习笔记:P12-程序结构
C语言程序设计学习笔记:P13-文件
C语言程序设计学习笔记:P14-链表
问题
问题引出: 上篇博客我们有一个例子,计算两个时间的差值。我们知道,如果直接将时间的小时和分钟分别相减,会出现分钟借位的情况:如1点40分和2点10分的差。针对这种情况,上篇博客我们的处理方案是将两个时间转为分钟,然后进行整数的相减。但是现在我就想用分别相减的方案,该怎么做呢?
解决方案: 这时我们会想,能不能判断出当前是否需要进行分钟的借位?如果需要借位,我们就做出相应的调整。于是,我们写出相应的代码如下所示:
代码实现
#include
int main()
{
int hour1, minute1;
int hour2, minute2;
scanf_s("%d %d", &hour1, &minute1);
scanf_s("%d %d", &hour2, &minute2);
int ih = hour2 - hour1;
int im = minute2 - minute1;
if (im < 0) {
im = 60 + im;
ih--;
}
printf("时间差是%d小时%d分。\n", ih, im);
return 0;
}
运行结果
在这段代码中,我们用了C语言中的条件判断。这里我们用的是
if
,如果im<0
,那么说明分钟数进行减法运算时发生了借位。那么我们要将im
加上60,给它补回去,同时让ih
减1。如果im>=0
,则不进行以上操作。我们运行一下,进行测试,可以看出结果正确。
if语句的作用
在程序执行过程中,这个if语句究竟如何起作用的呢?我们不妨设断点来查看一下。我们首先在if语句那一行设置一个断点,然后单步调试执行。
由于断点之前有两个scanf,所以我们首先需要输入两个时间。
此时我们可以看出各个im和ih的值已经计算出来了,而im的值小于0。
然后我们继续单步调试,使代码继续运行两行。此时我们可以看出if语句中的操作已经执行了,im和ih已经得到正确的值。
我们再次测试不用借位的情况,计算11点40和10点20的差值。此时各个变量的值如下所示。
我们再次向下调试一行,发现直接跳过if语句。
因此,if的使用原理就是:
if ( 条件成立 ) {
…
}
如果条件成立,则执行大括号里面的所有内容。如果不成立,则不执行大括号里面的内容。
在上面的代码中,我们在if语句的那个括号内使用了一个小于(<
)符号,用来计算两个值之间的关系,所以这种运算符叫做关系运算符。C语言的关系运算符如下表所示:
运算符 | 意义 |
---|---|
== | 相等 |
!= | 不相等 |
> | 大于 |
>= | 大于或等于 |
< | 小于 |
<= | 小于或等于 |
注: 切记,=
符号是赋值,==
才是判断是否相等。
示例
关系运算符的结果只有两个:0和1。如果这个关系成立,就是1。如果这个关系不成立,就是0。我们来看以下三个例子:
运行,可以看出结果正确。
关系运算符的优先级
既然关系运算符也是运算符,那么我们上篇博客说过,运算符都是有优先级的。所有的关系运算符的优先级比算术运算的低,但是比赋值运算的高。举例如下:
7 >= 3 + 4 首先计算3+4的值,然后判断7 >= 7,结果为1。
int r = a>0; 首先计算a>0的结果(1或0),然后将结果赋值给r。
而在所有的关系运算符中,他们的优先级也不是相同的。判断是否相等的==
和!=
的优先级比其他的低,同时连续的关系运算是从左到右进行的。举例如下:
5 > 3 == 6 > 4 这是在判断5>3和6>4的结果是否相等。
6 > 5 > 4 首先计算6>5的结果为1,然后计算1>4的结果为0。最终结果为0
a == b == 6 首先计算a==b的结果,然后计算其结果与6是否相等。最终结果一定为0
a == b > 0 首先判断b是否大于0,然后判断a是否等于b>0的结果。
示例:
上篇博客我们写过一个计算找零的代码,现在我们将其完善一下。找零计算器需要用户做两个操作:输入购买的金额,输入支付的票面,而找零计算器则根据用户的输入做出相应的动作:计算并打印找零,或告知用户余额不足以购买。从计算机程序的角度看,这就是意味着程序需要读用户的两个输入,然后进行一些计算和判断,最后输出结果。
基础代码实现
#include
int main()
{
// 初始化
int price = 0;
int bill = 0;
// 读入金额和票面
printf("请输入金额:");
scanf("%d", &price);
printf("请输入票面:");
scanf("%d", &bill);
// 计算找零
printf("应该找您:%d\n", bill - price);
return 0;
}
注释
在这段代码中,我们以两个斜杠
//
开头的语句把程序分成了三个部分:
1、初始化
2、读入金额和票面
3、计算并打印找零
----这样开头的东西我们叫做注释(comment)。注释插入在程序代码中,用来向读者提供解释信息。它们对于程序的功能没有任何影响,但是往往能使得程序更容易被人类读者理解。
----两个斜杠符号//
开头的只能注释单行,我们还有注释多行的符号:/* */
。多行注释由一对字符序列/*
开始,而以*/
结束。用法实例如下:
多行注释符号用法
/*
int a;
int b;
int c;
int d;
*/
改进
刚才的代码并没有去判断我们的票面够不够。也就是说,如果票面小于商品的金额,我们不应该找钱,否则找出来就是负数。因此,我们需要一个机制:当条件成立时,我们做什么。当条件不成立时,我们做什么。这个机制叫做else。因此当条件不满足时,我们可以使用else,输出“你的钱不够”。
完整代码实现
#include
int main()
{
// 初始化
int price = 0;
int bill = 0;
// 读入金额和票面
printf("请输入金额:");
scanf("%d", &price);
printf("请输入票面:");
scanf("%d", &bill);
// 计算找零
if ( bill >= price ) {
printf("应该找您:%d\n", bill - price);
} else {
printf("你的钱不够\n");
}
return 0;
}
运行结果
示例:比较两个数的大小
根据所学的知识,我们可以使用不同的方法来实现这个功能。这两种方案中,第一种方案较好,很明了。第二种方案虽然代码量少一些,但是不容易让人直接看得懂。
方案一代码:
#include
int main()
{
int a,b;
printf("请输入两个整数:");
scanf("%d %d", &a, &b);
int max = 0;
if ( a > b ) {
max = a;
}
else{
max = b;
}
printf("大的那个是%d\n", max);
return 0;
}
方案二代码:
#include
int main()
{
int a,b;
printf("请输入两个整数:");
scanf("%d %d", &a, &b);
int max = b;
if ( a > b ) {
max = a;
}
printf("大的那个是%d\n", max);
return 0;
}
if的两种形式
if的一般形式
通过前面的学习我们已经知道一个基本的if语句由一个关键字if开头,跟上在括号里的一个表示条件的逻辑表达式,然后是一对大括号{}之间的若干条语句。如果表示条件的逻辑表达式的结果不是零,那么就执行后面跟着的这对大括号中的语句,否则就跳过这些语句不执行,而继续下面的其他语句。
if的另外一种形式
值得小心的是,if语句还有另外一种形式,没有大括号,而是紧跟着一行代码。而这行代码就是条件成立时执行的东西。
示例:
用户输入工作的小时数,我们帮他计算薪水。我们有一些固定的值,每小时的薪水是8.25,每周工作时间为40小时。如果超过标准工作时间,需要支付1.5倍的工资。
代码实现
#include
int main()
{
const double RATE = 8.25;
const int STANDARD = 40;
double pay = 0.0;
int hours;
printf("请输入工作的小时数: ");
scanf("%d", &hours);
printf("\n");
if (hours > STANDARD)
pay = STANDARD * RATE +
(hours-STANDARD) * (RATE * 1.5);
else
pay = hours * RATE;
printf("应付工资: %f\n", pay);
return 0;
}
示例:
输入一个成绩,判断是否及格,及格的分数线设置为60。
代码实现
#include
int main()
{
const int PASS=60;
int score;
printf("请输入成绩: ");
scanf("%d", &score);
printf("你输入的成绩是%d.\n", score);
if ( score < PASS )
printf("很遗憾,这个成绩没有及格。");
else {
printf("祝贺你,这个成绩及格了。");
printf("再见\n");
}
return 0;
}
1、以下语句是否可以通过编译:
答案: 可以
2、以下语句是否表示n属于[1,10]:
答案:错误
嵌套的if语句
前面我们写了一个求两个数最大值的代码,而现在如果我有三个数要求出其中的最大值,我该怎么做?我们的方法是:首先比较a和b的大小。如果a大,则比较a和c的大小。如果b大,则比较b和c的大小。流程如下:
当if的条件满足或者不满足的时候要执行的语句也可以是一条if或if-else语句,这就是嵌套的if语句。
代码实现
#include
int main()
{
int a,b,c;
scanf("%d %d %d", &a, &b, &c);
int max = 0;
if ( a>b ) {
if ( a>c ) {
max = a;
} else {
max = c;
}
} else {
if ( b>c ) {
max = b;
} else {
max = c;
}
}
printf("The max is %d\n", max);
return 0;
}
由于if语句中需要执行的代码只有一行,那么也可以删除掉if语句中的大括号,代码如下:
#include
int main()
{
int a,b,c;
scanf("%d %d %d", &a, &b, &c);
int max = 0;
if ( a>b )
if ( a>c )
max = a;
else
max = c;
else
if ( b>c )
max = b;
else
max = c;
printf("The max is %d\n", max);
return 0;
}
if与else的对应关系
在上面代码中的嵌套if语句中,有好几个else,那么每个else对应哪个if呢?实际上,else总是和最近的那个if匹配。同样的,我们在代码中会看到各种各样的缩进,但是缩进格式不能暗示else的匹配。比如下面这种情况,这个else实际匹配的是
if (count <20)
。
但是如果加上大括号就不一样了,此时else匹配的就是if (code == READY)
因此,在使用if语句时,建议在if或else后面总是用{},即使只有一条语句的时候。
级联的if-else
使用方法:
if ( 条件1 )
语句1;
else if ( 条件2 )
语句2;
else
语句3;
现在我有一个分段函数,我们用if-else来解决。
代码实现
if (x<0){
f = -1;
}else if(x==0){
f=0;
}else{
f=2*x;
}
1、忘了大括号
现在有个案例。如果年龄大于60岁,则薪水增加为原来的1.2倍,同时将薪水的值打印出来。
if ( age > 60 )
salary = salary * 1.2;
printf("%f",salary);
可是我们没加大括号,导致是否年龄大于60岁,都会输出薪水值。因此,永远在if和else后面加上大括号,即使当时后面只有一条语句。
if( age > 60 )
{
salary = salary * 1.2;
printf("%f",salay);
}
2、在if后面多加了分号
在下面这段代码中,我们在if语句后面加了分号。
#include
int main()
{
int age = 55;
double salary = 4000;
if (age > 60);
{
salary = salary * 1.2;
printf("%f\n", salary);
}
return 0;
}
运行,发现我们输入的age小于60,但是仍然打印了新的薪水值。
这是因为对输入了一个分号导致程序变成了以下这种情况。即if后面有一条语句,可是这条语句什么都不做。因此,这条if什么都不做就结束了。然后下面的那些大括号就是一些正常的语句。
if (age > 60)
;
{
salary = salary * 1.2;
printf("%f\n", salary);
}
3、错误使用==和=
if只要求()里的值是零或非零。在这段代码中,我们只有一个等号,这就是个赋值,而赋值就是个表达式。这个表达式也会有个结果,这个结果就是b。但它还会有个副作用,那就是把b的值给a。但是它一定不会去判断b是否等于a。只要b的值不是0,这个if就是成立的,顺便还把a的值给改了。
if ( a = b )
{
printf("A=B");
}
我们举例来看一下。
#include
int main()
{
int age = 55;
double salary = 4000;
//这里我们把==改为=
if (age = 60);
{
salary = salary * 1.2;
printf("%d %f\n", age, salary);
}
return 0;
}
一些代码风格
为了保证if语句的正确性,一定要注意不要犯以上三种错误。同时,在if和else之后必须加上大括号形成语句块。大括号内的语句缩进一个tab的位置,使得结构更加清晰。下面三种代码风格均可以,知道遵循代码规则即可。
在前面我们使用了级联的if-else进行分段函数的计算。但有时候我们也会存在这种情况,比如当我的变量等于某一个值时执行对应的操作。这里我有一个案例,当type值不同时,输出不同的语句。
if ( type==1 )
printf("你好");
else if ( type==2)
printf("早上好");
else if ( type==3 )
printf("晚上好");
else if ( type==4 )
printf("再见");
else
printf("啊,什么啊?");
对于这种情况,如果运气不好我输入的type的值≥5,那么会逐次执行各个if语句。于是我们就可以写出这样的代码:
switch ( type ) {
case 1:
printf("你好");
break;
case 2:
printf("早上好");
break;
case 3:
printf("晚上好");
break;
case 4:
printf("再⻅见");
break;
default:
printf("啊,什么啊?");
}
这段代码做的内容是:根据type值取匹配各个case后面的值。如果type==1,那么我们就做case 1:
后面的内容,直到遇到break。如果type不等于1、2、3、4,那我们做default后面的句子。这便是switch-case语句,它的使用如下所示:
switch ( 控制表达式 ) {
case 常量:
语句;
case 常量:
语句;
default:
语句;
}
使用switch-case时的注意事项
①控制表达式只能是整数型的结果,常量可以是常数,也可以是常数计算的表达式。
②根据表达式的结果,寻找匹配的case,并执行case后面的语句,一直到break为止。
③在执行完对应case中的最后一条语句后,如果后面没有break,就会顺序执行到下面的case里去,直到遇到一个break,或者switch结束为止。
④如果所有的case都不匹配,那么就执行default后面的语句。如果没有default,那么就什么都不做。
针对以上需要注意的地方,我们举例说明。
switch ( type )
{
case 1:
case 2:
printf("你好\n");
break;
case 3:
printf("晚上好\n");
case 4:
printf("再见\n");
break;
default:
printf("啊,什么啊?\n");
break;
}
如果我们输入的type为1,而对应的case中什么都没有,然后顺序进入case2中去,打印出“你好”,结束。
如果我们输入的type为3,而对应的case中没有break,因此打印出“晚上好”后顺序进入case4中去,打印出“晚安”,结束。
示例1: 成绩转换。将100分的成绩转换为ABCDE五个等级。
#include
int main()
{
printf("输入成绩(0-100)");
int grade;
scanf("%d", &grade);
grade /=10;
switch ( grade ) {
case 10:
case 9:
printf("A\n");
break;
case 8:
printf("B\n");
break;
case 7:
printf("C\n");
break;
case 6:
printf("D\n");
break;
default:
printf("F\n");
break;
}
return 0;
}
示例2: 输出月份的英文。
#include
int main()
{
printf("请输入月份:");
int month;
scanf("%d", &month);
switch ( month )
{
case 1: printf("January\n"); break;
case 2: printf("February\n"); break;
case 3: printf("March\n"); break;
case 4: printf("April\n"); break;
case 5: printf("May\n"); break;
case 6: printf("June\n"); break;
case 7: printf("July\n"); break;
case 8: printf("August\n"); break;
case 9: printf("September\n"); break;
case 10:printf("October\n"); break;
case 11:printf("November\n"); break;
case 12:printf("December\n"); break;
}