【新书推荐】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://xiahunao.cn/news/2775832.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

【代码】Processing笔触手写板笔刷代码合集

代码来源于openprocessing&#xff0c;考虑到国内不是很好访问&#xff0c;我把我找到的比较好的搬运过来&#xff01; 合集 参考&#xff1a;https://openprocessing.org/sketch/793375 https://github.com/SourceOf0-HTML/processing-p5.js/tree/master 这个可以体验6种笔触…

Netty连接通道中的Channel参数模型

ChannelOption(Channel中的连接参数) ChannelOption.SOBACKLOG ChannelOption.SO_BACKLOG对应的是tcp/ip协议listen函数中的backlog参数&#xff0c;服务端处理客户端连接请求是顺序处理的&#xff0c;所以同一时间只能处理一个客户端连接&#xff0c;多个客户端来的时候&…

P1297 [国家集训队] 单选错位 对期望的理解

[国家集训队] 单选错位 - 洛谷 思路&#xff1a; 其实每个位置的得分只和前一个位置有关。 而他们俩的所有情况的期望就是答案的这部分。 ——这是难想的&#xff0c;我期望学的不好。 &#xff08;题目给的是每种情况的所有位置的和&#xff0c;全加起来是答案&#xff1…

【数据分享】1929-2023年全球站点的逐月平均风速(Shp\Excel\免费获取)

气象数据是在各项研究中都经常使用的数据&#xff0c;气象指标包括气温、风速、降水、能见度等指标&#xff0c;说到气象数据&#xff0c;最详细的气象数据是具体到气象监测站点的数据&#xff01; 有关气象指标的监测站点数据&#xff0c;之前我们分享过1929-2023年全球气象站…

ansible shell模块 可以用来使用shell 命令 支持管道符 shell 模块和 command 模块的区别

这里写目录标题 说明shell模块用法shell 模块和 command 模块的区别 说明 shell模块可以在远程主机上调用shell解释器运行命令&#xff0c;支持shell的各种功能&#xff0c;例如管道等 shell模块用法 ansible slave -m shell -a cat /etc/passwd | grep root # 可以使用管道…

边缘计算初创公司ZEDEDA获7200万美元C轮融资,助力边缘计算市场扩张!

边缘计算领域传来喜讯&#xff01; 边缘计算社区获悉&#xff0c;就在昨天&#xff08;2月7日&#xff09;&#xff0c;边缘计算企业ZEDEDA成功募集7200万美元C轮融资&#xff0c;折合人民币高达约5.18亿元。据悉&#xff0c;此次融资使ZEDEDA的估值飙升至4亿美元&#xff0c;相…

Java:内部类、枚举、泛型以及常用API --黑马笔记

内部类 内部类是类中的五大成分之一&#xff08;成员变量、方法、构造器、内部类、代码块&#xff09;&#xff0c;如果一个类定义在另一个类的内部&#xff0c;这个类就是内部类。 当一个类的内部&#xff0c;包含一个完整的事物&#xff0c;且这个事物没有必要单独设计时&a…

git flow与分支管理

git flow与分支管理 一、git flow是什么二、分支管理1、主分支Master2、开发分支Develop3、临时性分支功能分支预发布分支修补bug分支 三、分支管理最佳实践1、分支名义规划2、环境与分支3、分支图 四、git flow缺点 一、git flow是什么 Git 作为一个源码管理系统&#xff0c;…

JavaScript鼠标移动事件

&#x1f9d1;‍&#x1f393; 个人主页&#xff1a;《爱蹦跶的大A阿》 &#x1f525;当前正在更新专栏&#xff1a;《VUE》 、《JavaScript保姆级教程》、《krpano》、《krpano中文文档》 ​ ​ ✨ 前言 鼠标移动是用户界面中非常重要的交互行为。学习区分不同的鼠标移动事…

PySpark(三)RDD持久化、共享变量、Spark内核制度,Spark Shuffle、Spark执行流程

目录 RDD持久化 RDD 的数据是过程数据 RDD 缓存 RDD CheckPoint 共享变量 广播变量 累加器 Spark 内核调度 DAG DAG 的宽窄依赖和阶段划分 内存迭代计算 Spark是怎么做内存计算的? DAG的作用?Stage阶段划分的作用? Spark为什么比MapReduce快&#xff1f; Spa…

机器学习10-特征缩放

特征缩放的目的是确保不同特征的数值范围相近&#xff0c;使得模型在训练过程中更加稳定&#xff0c;加速模型收敛&#xff0c;提高模型性能。具体而言&#xff0c;零均值和单位方差的目标有以下几点好处&#xff1a; 1. 均值为零&#xff08;Zero Mean&#xff09;&#xff1a…

红队打靶练习:GLASGOW SMILE: 1.1

目录 信息收集 1、arp 2、nmap 3、nikto 4、whatweb 目录探测 1、gobuster 2、dirsearch WEB web信息收集 /how_to.txt /joomla CMS利用 1、爆破后台 2、登录 3、反弹shell 提权 系统信息收集 rob用户登录 abner用户 penguin用户 get root flag 信息收集…

【Python】使用 requirements.txt 与 pytorch 相关配置

【Python】使用 requirements.txt 与 pytorch 相关配置 前言一、pip1、导出结果含有路径2、导出不带路径的 二、Conda1、导出requirements.txt2、导出yml 文件 三、第三方包&#xff1a;pipreqs&#xff08;推荐&#xff09;1、创建并激活conda环境2、安装requirements文件的pi…

Linux进程间通信(2)--System V共享内存 | 消息队列 | 信号量

目录 实现原理 使用系统调用创建共享内存 使用shmget函数创建共享内存&#xff1a; 使用shmat函数将共享内挂接到进程地址空间的共享区 使用shmdt函数取消共享内存与进程地址空间的关联 ​编辑 使用shmctl函数释放共享内存 共享内存的属性 System V消息队列 &#xff…

文件上传-Webshell

Webshell简介 webshell就是以aspphpjsp或者cgi等网页文件形式存在的一种命令执行环境&#xff0c;也可以将其称做为一种网页木马后门。 攻击者可通过这种网页后门获得网站服务器操作权限&#xff0c;控制网站服务器以进行上传下载文件、查看数据库、执行命令等… 什么是木马 …

docker 基于容器创建本地web容器化镜像

一、docker 基于容器创建本地web容器化镜像 1、启动指定buysbox 镜像 docker run --name b1 -it busybox:latest 2、创建目录&#xff0c;并创建html mkdir -p /data/html vi index.html 内容自定义例如&#xff1a;<h1>welcome to busybox<h1> 3、新增窗口&am…

类和对象 第六部分第二小节:继承方式

前情提要&#xff1a;继承的语法&#xff1a;class 子类 继承方式&#xff1a;父类 继承方式一共有3种&#xff1a; 代码案例&#xff1a; 前置代码 #include<iostream> using namespace std; class Base1 { public:int m_A; protected:int m_B; private:int m_C; };公共…

linux C编程入门

Ubuntu 下也有一些可以进行编程的工具&#xff0c;但是大多都只是编辑器&#xff0c; 也就是只能进行代码编辑&#xff0c;如果要编译的话就需要用到 GCC 编译器&#xff0c;使用 GCC 编译器肯定就 要接触到Makefile。 1&#xff1a;hello world!!! 我们所说的编写代码包括两部…

Qt网络编程-TCP与UDP

网络基础 TCP与UDP基础 关于TCP与UDP的基础这里就不过多介绍了&#xff0c;具体可以查看对应百度百科介绍&#xff1a; TCP&#xff08;传输控制协议&#xff09;_百度百科 (baidu.com) UDP_百度百科 (baidu.com) 需要知道这两者的区别&#xff1a; 可靠性&#xff1a; TC…

day35 数组map和join方法(字符串拼接)

目录 map方法join方法 map方法 使用场景&#xff1a;map 可以遍历数组处理数据&#xff0c;并且返回新的数组map 也称为映射。映射是个术语&#xff0c;指两个元素的集之间元素相互“对应”的关系。map重点在于有返回值&#xff0c;forEach没有返回值&#xff08;undefined&am…