6.2 else if语句

本节必须掌握的知识点:

示例代码二十

代码分析

汇编解析

if 语句表达形式3

if(表达式1)

statement1

else if(表达式2)

statement2

else if(表达式3)

statement3

......

else

statementN

解析:

如果表达式1非0,则执行statement1,执行完退出语句;

如果表达式2非0,则执行statement2,执行完退出语句;

如果表达式3非0,则执行statement3,执行完退出语句;

如果表达式4非0,则执行statement4,执行完退出语句;

......

如果所有的表达式都不满足,则执行else对应的statement语句。

|--------|
| 示例代码二十 |

6.2.1 示例二十

●第一步:分析需求,设计程序结构框架。

分析需求:某中学考试成绩分为ABCDE 5个等级,在[90,100]区间内的成绩为A,在[80,90)区间内的成绩为B,在[70,80)区间内的成绩为C,在[60,70)区间内的成绩为D,在[0,60)区间内的成绩为E。

设计程序结构框架:分支结构(if语句形式3)if/else if语句。

●第二步:数据定义,定义恰当的数据结构;

int score;//定义一个int类型的整型局部变量。

●第三步:分析算法。

根据条件表达式判断考试分数属于哪个等级。

●第四步:编写伪代码,即用我们自己的语言来编写程序。

int main (void) {

定义一个int类型整型变量num;

调用printf函数打印一个提示信息"请输入一个整数:";

调用scanf_s 函数接收键盘输入一个整数,并存入变量num;

if (score >= 90 && score <= 100)如果条件为真

调用printf 函数输出"您在A等级\n";

else if (score >= 80 && score < 90) 如果条件为真

调用printf 函数输出"您在B等级\n";

else if (score >= 70 && score < 80) 如果条件为真

调用printf 函数输出"您在C等级\n";

else if (score >= 60 && score < 70) 如果条件为真

调用printf 函数输出"您在D等级\n";

else 其他情形

调用printf 函数输出"您在E等级\n";

system ("pause");

return 0;

}

●第五步:画流程图,使用Visio、Excel或者其他绘图工具绘制算法流程和逻辑关系图;

图6-3 示例二十流程图

●第六步:编写源程序,其实就是将我们的伪代码翻译成计算机语言;

/*

根据学生考试分数,输出ABCDE 5个等级

*/

#include <stdio.h>

#include <stdlib.h>

int main (void) {

int score = 0;

printf ("请输入您的成绩:");

scanf_s ("%d", &score);

if (score >= 90 && score <= 100)

printf ("您在A等级\n");

else if (score >= 80 && score < 90)

printf ("您在B等级\n");

else if (score >= 70 && score < 80)

printf ("您在C等级\n");

else if (score >= 60 && score < 70)

printf ("您在D等级\n");

else

printf ("您在E等级\n");

system ("pause");

return 0;

}

●输出结果:

请输入您的成绩:91

您在A等级

请输入您的成绩:81

您在B等级

请输入您的成绩:71

您在C等级

请输入您的成绩:61

您在D等级

请输入您的成绩:0

您在E等级

●第七步:调试程序,修复程序中可能出现的BUG;

参见反汇编代码。

●第八步:优化代码,尝试更好的设计方案,效率更高的算法,逻辑更为清晰简洁明了。

示例二十一中我们将改用if/else结构的简化形式switch结构。

6.2.2 代码分析

解析执行过程:

  1. 输入成绩,score = 71;虽然成绩通常不会是一个负整数,应该定义一个usigned int类型变量,这是对的。但是int类型可以表示的数据范围足够使用,所以这里并没有定义为usigned int类型,而是int类型也没什么问题。
  2. 执行表达式(score>=90 && score<=100),值为0,继续判断其他条件;
  3. 执行表达式(score>=80 && score<90),值为0,继续判断其他条件;

4、执行表达式(score>=70 && score<80),值为0,满足条件,执行对应的语句: printf("您在C等级\n"); 跳出if语句,不再判断其它if语句。

5、结束。

【注意】为了增强程序的可读性强,我们通常会保留大括号,如下所示:

#include <stdio.h>

#include <windows.h>

int main(void)

{

int score = 0;

printf("请输入您的成绩:");

|-----------------------------|
| 加上了程序界定符"{" "}" ,这样增强代码的可读性 |

scanf("%d",&score);

if(score>=90 && score<=100)

{

printf("您在A等级\n");

}

else if(score>=80 && score<90)

{

printf("您在B等级\n");

}

else if(score>=70 && score<80)

{

printf("您在C等级\n");

}

else if(score>=60 && score<70)

{

printf("您在D等级\n");

}

else

{

printf("您在E等级\n");

}

system("pause");

return 0;

}

6.2.3 汇编解析

汇编代码

;C标准库头文件和导入库

include vcIO.inc

.data

score sdword ?

.const

szMsg1 db "请输入您的成绩:",0

szMsg2 db "%d",0

szMsg3 db "您在A等级",0dh,0ah,0

szMsg4 db "您在B等级",0dh,0ah,0

szMsg5 db "您在C等级",0dh,0ah,0

szMsg6 db "您在D等级",0dh,0ah,0

szMsg7 db "您在E等级",0dh,0ah,0

.code

start:

;输入整数num

invoke printf,offset szMsg1

invoke scanf,offset szMsg2,ADDR score

;

.if (score >= 90 && score <= 100)

invoke printf,offset szMsg3

.elseif (score >= 80 && score < 90)

invoke printf,offset szMsg4

.elseif (score >= 70 && score < 80)

invoke printf,offset szMsg5

.elseif (score >= 60 && score < 70)

invoke printf,offset szMsg6

.else

invoke printf,offset szMsg7

.endif

;

invoke _getch

ret

end start

上述汇编代码使用了高级汇编伪指令.if/.elseif/.else,竟然与C语言的语法如此的相似,很难不让人怀疑,C语言的发明人是否借鉴了高级汇编的语法。当然我们也可以理解为什么有人会将C语言称为高级汇编语言了。

为了彻底搞清楚计算机是如何实现这些分支结构的条件判断,我们还是看一看反汇编代码,了解计算机的具体实现过程。

反汇编代码

int score = 0;

00B51952 mov dword ptr [score],0

printf("请输入您的成绩:");

00B51959 push offset string "\xc7\xeb\xca\xe4\xc8\xeb\xc4\xfa\xb5\xc4\xb3\xc9\xbc\xa8\xa3\xba" (0B57B30h)

00B5195E call _printf (0B5104Bh)

00B51963 add esp,4

scanf_s("%d", &score);

00B51966 lea eax,[score]

00B51969 push eax

00B5196A push offset string "%d" (0B57B44h)

00B5196F call _scanf_s (0B51154h)

00B51974 add esp,8

if (score >= 90 && score <= 100)

00B51977 cmp dword ptr [score],5Ah ;比较score和90的大小

00B5197B jl main+72h (0B51992h) ;如果score<90则跳转到下一个else if语句

00B5197D cmp dword ptr [score],64h ;比较score和100的大小

00B51981 jg main+72h (0B51992h) ;如果score>100则跳转到下一个else if语句

printf("您在A等级\n") ;90<=score<=100则执行下面的printf语句

00B51983 push offset string "\xc4\xfa\xd4\xdaA\xb5\xc8\xbc\xb6\n" (0B57B48h)

00B51988 call _printf (0B5104Bh)

00B5198D add esp,4

00B51990 jmp main+0D0h (0B519F0h)

else if (score >= 80 && score < 90)

00B51992 cmp dword ptr [score],50h

00B51996 jl main+8Dh (0B519ADh) ;jl****小于

00B51998 cmp dword ptr [score],5Ah

00B5199C jge main+8Dh (0B519ADh) ;jg****大于等于

printf("您在B等级\n");

00B5199E push offset string "\xc4\xfa\xd4\xdaB\xb5\xc8\xbc\xb6\n" (0B57B58h)

00B519A3 call _printf (0B5104Bh)

00B519A8 add esp,4

00B519AB jmp main+0D0h (0B519F0h)

else if (score >= 70 && score < 80)

00B519AD cmp dword ptr [score],46h

00B519B1 jl main+0A8h (0B519C8h)

00B519B3 cmp dword ptr [score],50h

00B519B7 jge main+0A8h (0B519C8h)

printf("您在C等级\n");

00B519B9 push offset string "\xc4\xfa\xd4\xdaC\xb5\xc8\xbc\xb6\n" (0B57B68h)

printf("您在C等级\n");

00B519BE call _printf (0B5104Bh)

00B519C3 add esp,4

00B519C6 jmp main+0D0h (0B519F0h)

else if (score >= 60 && score < 70)

00B519C8 cmp dword ptr [score],3Ch

00B519CC jl main+0C3h (0B519E3h)

00B519CE cmp dword ptr [score],46h

00B519D2 jge main+0C3h (0B519E3h)

printf("您在D等级\n");

00B519D4 push offset string "\xc4\xfa\xd4\xdaD\xb5\xc8\xbc\xb6\n" (0B57B78h)

00B519D9 call _printf (0B5104Bh)

00B519DE add esp,4

00B519E1 jmp main+0D0h (0B519F0h)

else

printf("您在E等级\n");

00B519E3 push offset string "\xc4\xfa\xd4\xdaE\xb5\xc8\xbc\xb6\n" (0B57B88h)

00B519E8 call _printf (0B5104Bh)

00B519ED add esp,4

由上述反汇编代码可知,C语言的if/else if分支结构由一系列的cmp/jcc条件判断指令实现的。例如:

if (score >= 90 && score <= 100)

00B51977 cmp dword ptr [score],5Ah ;比较score和90的大小

00B5197B jl main+72h (0B51992h) ;如果score<90则跳转到下一个else if语句

00B5197D cmp dword ptr [score],64h ;比较score和100的大小

00B51981 jg main+72h (0B51992h) ;如果score>100则跳转到下一个else if语句

printf("您在A等级\n") ;90<=score<=100则执行下面的printf语句

00B51983 push offset string "\xc4\xfa\xd4\xdaA\xb5\xc8\xbc\xb6\n" (0B57B48h)

00B51988 call _printf (0B5104Bh)

00B5198D add esp,4

00B51990 jmp main+0D0h (0B519F0h)

else if (score >= 80 && score < 90)

00B51992 cmp dword ptr [score],50h

结论

C语言中的if/else if语句就是一系列CMP/JCC指令的连续判断,大大简化了代码。反汇编代码就是编译器将C语言翻译后的汇编代码。

实验三十六: 跟踪调试示例程序

第一步:打开DtDebug调试器,将示例二十生成的MyProjectOne.exe程序拖入调试器。

第二步:按Ctrl+F9,进入程序入口地址,如图6-4所示。

图6-4 进入程序入口地址

第三步:按F8,跳转到0x00c92380地址处,发现只有一个call语句,如图6-5所示。连续按3次F7或者直接选中call语句,点击鼠标右键,选中fllow跟随,进入call函数内部。

图6-5 F7单步步入函数内

第四步:进入call函数内部,如果6-6所示,此函数内有两个call语句。先按F8单步步过测试一下,第一个call没有反应,执行完第二个call语句时,控制台窗口显示提示信息:

"请输入您的成绩:"。

图6-6 F8 call测试

第五步:点击左上角工具栏

图标,重新来过,重复前面的1,2,3步,第4步至第二个call语句时,改用F7单步步入,如图6-7所示。

图6-7 F7单步步入第二个call函数

图6-8 锁定程序代码段的真实开始地址处

第六步:继续按F8测试,直至控制台窗口出现提示信息"请输入您的成绩:"。锁定地址0x00c92172地址处的call语句(每次调试加载程序的地址会有不同),鼠标选中后按F2,这该地址处下软件断点。如图6-8所示。

第七步:再次重新加载调试程序,连续点击两次左上角工具栏

图标执行程序,在0x00c92172地址处断下。然后按F7单步步入。

第八步:继续按F8测试,锁定最后一个call语句输出提示信息。然后在地址0x00c92309地址处按F2下断点。如图6-9所示。

图6-9 锁定最终的入口函数

第九步:重新来过,连续执行至0x00c92309地址处,按F7单步步入,然后再按一次F7跳转到main函数内,如下所示:

|--------|
| 建立堆栈框架 |

00C91920 55 PUSH EBP

00C91921 8BEC MOV EBP,ESP

00C91923 81EC D0000000 SUB ESP,0D0

|-------|
| 保护寄存器 |

00C91929 53 PUSH EBX

00C9192A 56 PUSH ESI

00C9192B 57 PUSH EDI

00C9192C 8DBD 30FFFFFF LEA EDI,DWORD PTR SS:[EBP-D0]

|-------|
| 初始化堆栈 |

00C91932 B9 34000000 MOV ECX,34

00C91937 B8 CCCCCCCC MOV EAX,CCCCCCCC

00C9193C F3:AB REP STOS DWORD PTR ES:[EDI]

00C9193E A1 04A0C900 MOV EAX,DWORD PTR DS:[C9A004]

00C91943 33C5 XOR EAX,EBP

00C91945 8945 FC MOV DWORD PTR SS:[EBP-4],EAX

00C91948 B9 03C0C900 MOV ECX,MyProjec.00C9C003

00C9194D E8 CFF8FFFF CALL MyProjec.00C91221

00C91952 C745 F4 0000000>MOV DWORD PTR SS:[EBP-C],0

以上00C9193E~00C91952地址处的代码为编译器添加的校验代码,此处不做介绍。

printf ("请输入您的成绩:");

|----------|
| printf函数 |

00C91959 68 307BC900 PUSH MyProjec.00C97B30

00C9195E E8 E8F6FFFF CALL MyProjec.00C9104B

00C91963 83C4 04 ADD ESP,4

00C91966 8D45 F4 LEA EAX,DWORD PTR SS:[EBP-C]

scanf_s ("%d", &score);

|---------|
| scanf函数 |

00C91969 50 PUSH EAX

00C9196A 68 447BC900 PUSH MyProjec.00C97B44 ; ASCII "%d"

00C9196F E8 E0F7FFFF CALL MyProjec.00C91154

00C91974 83C4 08 ADD ESP,8

if (score >= 90 && score <= 100)

00C91977 837D F4 5A CMP DWORD PTR SS:[EBP-C],5A

|----------|
| If语句条件判断 |

00C9197B 7C 15 JL SHORT MyProjec.00C91992

00C9197D 837D F4 64 CMP DWORD PTR SS:[EBP-C],64

00C91981 7F 0F JG SHORT MyProjec.00C91992

printf ("您在A等级\n");

|----------|
| printf函数 |

00C91983 68 487BC900 PUSH MyProjec.00C97B48

00C91988 E8 BEF6FFFF CALL MyProjec.00C9104B

00C9198D 83C4 04 ADD ESP,4

00C91990 EB 5E JMP SHORT MyProjec.00C919F0

else if (score >= 80 && score < 90)

00C91992 837D F4 50 CMP DWORD PTR SS:[EBP-C],50

00C91996 7C 15 JL SHORT MyProjec.00C919AD

00C91998 837D F4 5A CMP DWORD PTR SS:[EBP-C],5A

00C9199C 7D 0F JGE SHORT MyProjec.00C919AD

printf ("您在B等级\n");

00C9199E 68 587BC900 PUSH MyProjec.00C97B58

00C919A3 E8 A3F6FFFF CALL MyProjec.00C9104B

00C919A8 83C4 04 ADD ESP,4

00C919AB EB 43 JMP SHORT MyProjec.00C919F0

else if (score >= 70 && score < 80)

00C919AD 837D F4 46 CMP DWORD PTR SS:[EBP-C],46

00C919B1 7C 15 JL SHORT MyProjec.00C919C8

00C919B3 837D F4 50 CMP DWORD PTR SS:[EBP-C],50

00C919B7 7D 0F JGE SHORT MyProjec.00C919C8

printf ("您在C等级\n");

00C919B9 68 687BC900 PUSH MyProjec.00C97B68

00C919BE E8 88F6FFFF CALL MyProjec.00C9104B

00C919C3 83C4 04 ADD ESP,4

00C919C6 EB 28 JMP SHORT MyProjec.00C919F0

else if (score >= 60 && score < 70)

00C919C8 837D F4 3C CMP DWORD PTR SS:[EBP-C],3C

00C919CC 7C 15 JL SHORT MyProjec.00C919E3

00C919CE 837D F4 46 CMP DWORD PTR SS:[EBP-C],46

00C919D2 7D 0F JGE SHORT MyProjec.00C919E3

printf ("您在D等级\n");

00C919D4 68 787BC900 PUSH MyProjec.00C97B78

00C919D9 E8 6DF6FFFF CALL MyProjec.00C9104B

00C919DE 83C4 04 ADD ESP,4

00C919E1 EB 0D JMP SHORT MyProjec.00C919F0

printf ("您在E等级\n");

00C919E3 68 887BC900 PUSH MyProjec.00C97B88

00C919E8 E8 5EF6FFFF CALL MyProjec.00C9104B

00C919ED 83C4 04 ADD ESP,4

system ("pause");

00C919F0 8BF4 MOV ESI,ESP

00C919F2 68 987BC900 PUSH MyProjec.00C97B98 ; ASCII "pause"

00C919F7 FF15 68B1C900 CALL NEAR DWORD PTR DS:[C9B168] ; ucrtbase.system

00C919FD 83C4 04 ADD ESP,4

练习

1、2月14号情人节,男孩为了表白自己心爱的女生,买了一束花,女生收到花后,询问男生花的价格,如果花的价格大于999元,女生回复同意交往;如果花的价格大于等于99元且小于999元,女生回复我们可以做朋友;如果花的价格大于50元且小于99元,女生回复我们改天再约吧!其它价格,女生则直接挂电话。题目要求:必须有题目分析步骤、流程图、请用C语言中if语句写出来。

2、请写出来下面的汇编对应的C语言代码。

00401010 push ebp

00401011 mov ebp,esp

00401013 sub esp,44h

00401016 push ebx

00401017 push esi

00401018 push edi

00401019 lea edi,[ebp-44h]

0040101C mov ecx,11h

00401021 mov eax,0CCCCCCCCh

00401026 rep stos dword ptr [edi]

00401028 mov dword ptr [ebp-4],0

0040102F push offset string

"\xc7\xeb\xca\xe4\xc8\xeb\xc4\xfa\xb5\xc4\xb3\xc9\xbc\xa8\xa3\xba" (004240

00401034 call printf (00401290)

00401039 add esp,4

0040103C lea eax,[ebp-4]

0040103F push eax

00401040 push offset string "%d" (00424074)

00401045 call scanf (00401230)

0040104A add esp,8

0040104D cmp dword ptr [ebp-4],5Ah

00401051 jg main+4Fh (0040105f)

00401053 cmp dword ptr [ebp-4],64h

00401057 jne main+5Eh (0040106e)

00401059 cmp dword ptr [ebp-4],64h

0040105D jge main+5Eh (0040106e)

0040105F push offset string "\xc4\xfa\xd4\xdaA\xb5\xc8\xbc\xb6\n" (00424064)

00401064 call printf (00401290)

00401069 add esp,4

0040106C jmp main+0CEh (004010de)

0040106E cmp dword ptr [ebp-4],50h

00401072 jg main+70h (00401080)

00401074 cmp dword ptr [ebp-4],5Ah

00401078 jne main+7Fh (0040108f)

0040107A cmp dword ptr [ebp-4],5Ah

0040107E jge main+7Fh (0040108f)

00401080 push offset string "\xc4\xfa\xd4\xdaB\xb5\xc8\xbc\xb6\n" (00424054)

00401085 call printf (00401290)

0040108A add esp,4

0040108D jmp main+0CEh (004010de)

0040108F cmp dword ptr [ebp-4],46h

00401093 jg main+91h (004010a1)

00401095 cmp dword ptr [ebp-4],50h

00401099 jne main+0A0h (004010b0)

0040109B cmp dword ptr [ebp-4],50h

0040109F jge main+0A0h (004010b0)

004010A1 push offset string "\xc4\xfa\xd4\xdaC\xb5\xc8\xbc\xb6\n" (00424044)

004010A6 call printf (00401290)

004010AB add esp,4

004010AE jmp main+0CEh (004010de)

004010B0 cmp dword ptr [ebp-4],3Ch

004010B4 jg main+0B2h (004010c2)

004010B6 cmp dword ptr [ebp-4],46h

004010BA jne main+0C1h (004010d1)

004010BC cmp dword ptr [ebp-4],46h

004010C0 jge main+0C1h (004010d1)

004010C2 push offset string "\xc4\xfa\xd4\xdaD\xb5\xc8\xbc\xb6\n" (00424034)

004010C7 call printf (00401290)

004010CC add esp,4

004010CF jmp main+0CEh (004010de)

004010D1 push offset string "\xc4\xfa\xd4\xdaE\xb5\xc8\xbc\xb6\n" (00424024)

004010D6 call printf (00401290)

004010DB add esp,4

004010DE push offset string "pause" (0042401c)

004010E3 call system (00401120)

004010E8 add esp,4

004010EB xor eax,eax

3、任意输入三个实数,将a、b、c三个数看作三个线段,判断a、b、c能否构成三角形。题目要求:必须有题目分析步骤、流程图、代码。额外要求:自己写的代码务必切到反汇编窗口,并理解每句代码对应的汇编。

4、编写一段程序,输入两个整数值,如何后者是前者的约数,则显示"B是A的约数"。

如果不是,则显示"B不是A的约数"。

5、判断输入的值是否为0。

6、判断输入的整数的个位数是否为5?

7、判断输入的整数是负数、正数还是0?

8、输入一个整数,并显示它的绝对值。

9、判断输入两个整数的大小。

相关推荐
Dontla34 分钟前
Rust泛型系统类型推导原理(Rust类型推导、泛型类型推导、泛型推导)为什么在某些情况必须手动添加泛型特征约束?(泛型trait约束)
开发语言·算法·rust
Ttang2340 分钟前
Leetcode:118. 杨辉三角——Java数学法求解
算法·leetcode
喜欢打篮球的普通人41 分钟前
rust模式和匹配
java·算法·rust
java小吕布1 小时前
Java中的排序算法:探索与比较
java·后端·算法·排序算法
杜若南星1 小时前
保研考研机试攻略(满分篇):第二章——满分之路上(1)
数据结构·c++·经验分享·笔记·考研·算法·贪心算法
路遇晚风1 小时前
力扣=Mysql-3322- 英超积分榜排名 III(中等)
mysql·算法·leetcode·职场和发展
Neophyte06081 小时前
C++算法练习-day40——617.合并二叉树
开发语言·c++·算法
木向1 小时前
leetcode104:二叉树的最大深度
算法·leetcode
一个不喜欢and不会代码的码农1 小时前
力扣113:路径总和II
算法·leetcode