【新书推荐】7.2 while语句

本节必须掌握的知识点:

    掌握if语句语法

        熟练使用if语句

7.2.1 示例二十三

while语句其语法形式:

while(表达式)

{

语句块;

}

●语法解析:

第一步:执行表达式,如果表达式为真,则执行第二步;

第二步:执行语句块;

第三步:跳转到第一步,重复第一步的动作,判断表达式是否为真,为真则执行第二步,为假则结束while循环。

示例代码二十三

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

分析需求:构建一个while循环语句,当n>5时,重复执行while语句内的重复块。

设计程序结构框架:循环结构while语句。

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

       int n;//定义一个int类型的整型局部变量,并初始化为5。

       ●第三步:分析算法。

       利用while语句,当n>5时,重复执行while语句内的重复块。先判断后执行。

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

       int main(void) {

    定义一个int类型整型循环变量n=5;

    while(n>5)当n>5时执行大括号内的循环语句块{

        调用printf函数打印一个提示信息"n > 5\n"

        n++;                                  

}

调用printf函数打印一个提示信息"n <= 5\n"

system("pause");

    return 0;                                                                                                    

}

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

图7-2 示例二十三while循环语句

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

/*

   while语句

*/

#include <stdio.h>

#include <stdlib.h>

int main(void) {

    int n = 5;//循环变量

    while (n > 5)

    {

        printf("n > 5\n");

n++;

    }

    printf("n <= 5\n");

    system("pause");

    return 0;                      

}    

●输出结果:

n <= 5

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

参见反汇编代码。

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

示例二十三并没有真正的执行while循环语句块,这样就失去了while语句的意义。我们

将在示例四十四中实现真正的while循环。

7.2.2 代码分析

首先定义一个int型循环变量n,并赋初始值为5,每循环一次,n的值加1。

然后判断while语句的条件表达式是否为真。表达式为n>5,而我们定义的n的值等于5,而不是不大于5,所以表达式为假,不执行while语句里面的重复语句块;

跳过while循环语句块,直接执行代码printf(“n<=5”);

7.2.3 汇编解析

汇编代码

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

include vcIO.inc

.data

n sdword  5

.const    

szMsg1 db "n > 5",0dh,0ah,0

szMsg2 db "n <= 5",0dh,0ah,0

.code     

start:

NEXT:    

       ;(n > 5)

       .if n > 5

              invoke printf,offset szMsg1        

              inc sdword ptr n;

              jmp NEXT            

       .endif            

       ;

       invoke printf,offset szMsg2

       ;     

       invoke _getch

       ret                       

end start

       ●输出结果:

n <= 5

上述汇编代码中,当n>5条件成立时,会执行.if和.endif之间的语句块;如果条件为假,则直接跳过重复语句块,直接输出下面的szMsg2。我们会发现,C语言的while语句尽然可以使用.if条件语句+jmp指令实现。其实这很正常,不论是if语句、do while语句还是while语句对应的汇编指令都是JCC条件判断指令。接下来我们做一个实验。

实验四十三:.while高级汇编语句

用.while高级汇编语句实现C语言中的while语句:

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

include vcIO.inc

.data

n sdword  5

.const    

szMsg1 db "n > 5",0dh,0ah,0

szMsg2 db "n <= 5",0dh,0ah,0

.code     

start:

NEXT:    

       ;(n > 5)

       .while n > 5

              invoke printf,offset szMsg1        

              inc sdword ptr n;

              ;jmp NEXT    ;去掉     

       .endw           

       ;

       invoke printf,offset szMsg2

       ;     

       invoke _getch

       ret                       

end start

区别于7-2-1.asm中使用.if/.endif语句实现while循环,上述汇编代码使用了高级汇编伪指令.while/.endw实现while循环。除了伪指令变化之外,一个最重要的区别就是重复块语句中去掉了jmp NEXT语句,很显然这是编译器隐含的实现代码。为了证明“不论是if语句、do while语句还是while语句对应的汇编指令都是JCC条件判断指令”这句话的正确性,我们来分析一下反汇编代码的实现。

反汇编代码

           int n = 5;

01211838  mov         dword ptr [n],5 

        while (n > 5)

0121183F  cmp         dword ptr [n],5  ;先比较n和5的大小

01211843  jle         main+4Dh (0121185Dh;如果b<=5,则跳转到地址0121185Dh处

    {

        printf("n > 5\n");否则执行下面的重复语句块

01211845  push        offset string "n > 5\n" (01217BE0h) 

0121184A  call        _printf (0121104Bh) 

0121184F  add         esp,4 

        n++;

01211852  mov         eax,dword ptr [n] 

01211855  add         eax,1 

01211858  mov         dword ptr [n],eax 

    }

0121185B  jmp         main+2Fh (0121183Fh;无条件跳转到0121183Fh处

    printf("n <= 5\n");

0121185D  push        offset string "n <= 5\n" (01217B34h) 

01211862  call        _printf (0121104Bh) 

01211867  add         esp,4 

    system("pause");

0121186A  mov         esi,esp 

0121186C  push        offset string "pause" (01217B3Ch) 

01211871  call        dword ptr [__imp__system (0121B168h)] 

01211877  add         esp,4 

       上述反汇编代码先判断n和5的大小,如果b<=5,则跳转到地址0121185Dh处,跳过重复语句块,直接执行第二个printf语句。

       在重复语句块内,通过无条件跳转指令jmp跳转到while语句的起始位置,再次比较n和5的大小。

实验四十四:实现while语句循环

在VS中新建项目7-2-2.c:

/*

   while语句

*/

#include <stdio.h>

#include <stdlib.h>

int main(void) {

    int n = 6;

    while (n > 5)

    {

        printf("n > 5\n");

        n++;

    }

    printf("n <= 5\n");

    system("pause");

    return 0;

}

●输出结果:

n > 5

n > 5

n > 5

n > 5

n > 5

n > 5

陷入死循环。

●代码分析:

1.定义int型变量n,并赋初始值为6。

2.while语句是先判断表达式是否为真,表达式为n>5,而我们定义的n的值是6,所以6>5,所以表达式为真,执行while语句里面的语句块。

  3.执行代码printf(“n>5”);n++;

  4、进入下轮循环,判断while语句的表达式n>5,而n的值加1后为7,7>6,表达式为真,执行while语句里面的语句块;

  5、执行代码printf(“n>5”);

……

一直反复执行,步骤2、3、形成一个死循环,直到内存溢出。

●反汇编:

    int n = 6;

00331838  mov         dword ptr [n],6 

    while (n > 5)

0033183F  cmp         dword ptr [n],5 

00331843  jle         main+4Dh (033185Dh)  ;n始终大于5

    {

        printf("n > 5\n");

00331845  push        offset string "n > 5\n" (0337B30h) 

0033184A  call        _printf (033104Bh) 

0033184F  add         esp,4 

        n++;

00331852  mov         eax,dword ptr [n] 

00331855  add         eax,1 

00331858  mov         dword ptr [n],eax 

    }

0033185B  jmp         main+2Fh (033183Fh)  ;无限循环

    printf("n <= 5\n");

0033185D  push        offset string "n <= 5\n" (0337B38h) 

00331862  call        _printf (033104Bh) 

00331867  add         esp,4 

通过上面的代码分析,示例代码将无限循环下去,那么问题来了,我们该如何让其代码摆脱死循环呢?当然解决办法有很多种,给循环语句加上退出条件即可。接下来我们继续做一个实验。

实验四十五:实现while语句循环退出

在VS中新建项目7-2-3.c:

/*

   while语句退出循环

*/

#include <stdio.h>

#include <stdlib.h>

int main(void) {

    int n = 6;

    while (n > 5)

    {

        printf("n > 5\n");

        n--;

    }

    printf("n <= 5\n");

    system("pause");

    return 0;

}

●输出结果:

n > 5

n <= 5

实验四十五的代码中,当第一次循环时,n的值为6,大于5,条件成立,执行循环语句,输出“n>5”;

“n--;”执行后,n=5,再次跳转到while语句的起始位置,此时“n>5”条件为假,while循环结束,输出“n<=5”。

 

结论

       1.while语句是先判断再执行,如果条件为真,执行循环语句块;如果条件为假,则退出循环,执行循环语句块之后的语句。

       2.使用while语句时,需要特别注意,防止陷入死循环。循环条件的设置应该趋近于结束循环。

       3.while语句和do while语句、if语句从本质上都是一致的,还原成汇编语句都是由条件CMP/JCC指令和无条件JMP指令的实现。

练习

  1. 请读者书写程序7-2-3.c伪代码,并绘制流程图。
  2. 请读者将7-2-3.c翻译成汇编语言实现。
  3. 请读者分析7-2-3.c的反汇编代码。

实验四十六: while语句循环变量递增1

在VS中新建项目7-2-4.c:

/*

   while语句循环变量递增1

*/

#include <stdio.h>

#include <stdlib.h>

int main(void) {

    int i = 0;

    while (i <= 20)

    {

        printf("i = %d\t",i);

        i++;//循环变量递增1

    }

    printf("\n");

    system("pause");

    return 0;

}

●输出结果:

i = 0   i = 1   i = 2   i = 3   i = 4   i = 5   i = 6   i = 7   i = 8   i = 9   i = 10  i = 11  i = 12  i = 13  i = 14  i = 15  i = 16  i = 17  i = 18  i = 19  i = 20

请读者自行分析上述代码的反汇编代码。

实验四十七: while语句循环变量递减2

在VS中新建项目7-2-5.c:

/*

   while语句循环变量递减2

*/

#include <stdio.h>

#include <stdlib.h>

int main(void) {

    int i = 20;

    while (i >= 0)

    {

        printf("i = %d\t", i);

        i -= 2;//复合运算符,循环变量递减2

    }

    printf("\n");

    system("pause");

    return 0;

}

●输出结果:

i = 20  i = 18  i = 16  i = 14  i = 12  i = 10  i = 8   i = 6   i = 4   i = 2   i = 0

上面代码请读者朋友动手分析,且能自己写出来大概的汇编代码,如果分析对了且汇编代码也写对了,那么while语句对你来说就是小菜一碟了。其实在实际的工作中,都是在这些基础语法上增加点代码块,俗话说:不积跬步无以至千里,所以一定要打好基础。

练习

       1、从输入的整数开始倒数到0。

2、从输入的整数开始倒数到1。

3、递增显示从0到输入的正整数为止的各个整数。

4、编写一段程序,按照升序显示出小于输入值的所以正偶数。

5、编写一段程序,按照升序显示出小于输入值的整数的所有2的乘方。

6、输入一个整数,连续显示出该整数个*。

7、输入规定数量个整数并显示出它们的合计值和平均值。

8、请输入一个正整数:1963,该整数逆向显示的结果是3691。

9、编写一个程序,读取一个正整数,显示其位数。

本文摘自编程达人系列教材《汇编的角度——C语言》。资料下载:www.bcdaren.com

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/462170.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PointBeV:A Sparse Approach to BeV Predictions

参考代码&#xff1a;PointBeV 动机与出发点 常见显式构建BEV特征的算法会稠密设置BEV网格&#xff0c;这样就会引入背景像素上的无效计算&#xff0c;对应内存与计算资源使用也会变大。这篇文章通过前景点筛选、由粗到精细化、窗口时序融合方式构建一种稀疏化表达的BEV特征表…

JSP编程

JSP编程 您需要理解在JSP API的类和接口中定义的用于创建JSP应用程序的各种方法的用法。此外,还要了解各种JSP组件,如在前一部分中学习的JSP动作、JSP指令及JSP脚本。JSP API中定义的类提供了可借助隐式对象通过JSP页面访问的方法。 1. JSP API的类 JSP API是一个可用于创建…

内网穿透工具

1. nps-npc 1.1 简介 nps是一款轻量级、高性能、功能强大的内网穿透代理服务器。目前支持tcp、udp流量转发&#xff0c;可支持任何tcp、udp上层协议&#xff08;访问内网网站、本地支付接口调试、ssh访问、远程桌面&#xff0c;内网dns解析等等……&#xff09;&#xff0c…

话题:IT行业有哪些证书含金量高?

IT行业有哪些证书含金量高? 1. 以下是一些在IT行业中我认为具有高含金量的证书&#xff1a; 思科认证&#xff08;Cisco Certifications&#xff09;&#xff1a;思科认证是由网络领域的著名厂商——Cisco公司推出的&#xff0c;是互联网领域的国际权威认证。这个认证体系包含…

基于Linux操作系统的Docker容器安装MySQL随笔

1、在Linux上安装Docker容器 cd /etc/yum.repos.d/ curl -O https://download.docker.com/linux/centos/docker-ce.repo sed -i s/$releasever/8/g docker-ce.repo yum install -y docker-ce 2、修改Docker默认镜像仓库&#xff0c;然后启动Docker容器 sudo mkdir -p /etc/do…

表单标记(html)

前言 发现input的type属性还是有挺多的&#xff0c;这里把一些常用的总结一下。 HTML 输入类型 (w3school.com.cn)https://www.w3school.com.cn/html/html_form_input_types.asp text-文本 文本输入,如果文字太长&#xff0c;超出的部分就不会显示。 定义供文本输入的单行…

【原创 附源码】Flutter海外登录--Tiktok登录最详细流程

最近接触了几个海外登录的平台&#xff0c;踩了很多坑&#xff0c;也总结了很多东西&#xff0c;决定记录下来给路过的兄弟坐个参考&#xff0c;也留着以后留着回顾。更新时间为2024年2月7日&#xff0c;后续集成方式可能会有变动&#xff0c;所以目前的集成流程仅供参考&#…

【 buuctf--刷新过的图片】

前言&#xff1a;这题主要运用到了新的工具F5-steganography由于 java 环境不合适的原因&#xff0c;我不得不重新配java11.0.18。 具体思路&#xff1a;非常帅气的一张图片。。。用 binwalk&#xff0c;stegsolve&#xff0c;zsteg&#xff0c;exiftool 等工具无果后&#xf…

按键扫描16Hz-单片机通用模板

按键扫描16Hz-单片机通用模板 一、按键扫描的原理1、直接检测高低电平类型2、矩阵扫描类型3、ADC检测类型二、key.c的实现1、void keyScan(void) 按键扫描函数①void FHiKey(void) 按键按下功能②void FSameKey(void) 按键长按功能③void FLowKey(void) 按键释放功能三、key.h的…

C++自定义函数详解

个人主页&#xff1a;PingdiGuo_guo 收录专栏&#xff1a;C干货专栏 铁汁们新年好呀&#xff0c;今天我们来了解自定义函数。 文章目录 1.数学中的函数 2.什么是自定义函数 3.自定义函数如何使用&#xff1f; 4.值传递和引用传递&#xff08;形参和实参区分&#xff09; …

macbookair怎么清理内存 ?如何利用 CleanMyMac X 进行系统清理

macbookair怎么清理内存 清理MacBook Air的内存可以通过以下几种方法&#xff1a; 优化储存空间。在MacBook Air上&#xff0c;可以通过“优化储存空间”来释放空间。这包括将文件储存在iCloud中&#xff0c;如桌面、文稿和iCloud信息&#xff0c;以及自动移除在iCloud中观看…

懒人精灵 之 Lua 捕获 json解析异常 ,造成的脚本停止.

Time: 2024年2月8日20:21:17 by:MemoryErHero 1 异常代码 Expected value but found T_END at character 12 异常代码 Expected value but found T_OBJ_END at character 223 处理方案 - 正确 json 示范 while true do--Expected value but found T_END at character 1--Ex…