【新书推荐】7.2 while语句

news2025/1/21 5:50:30

本节必须掌握的知识点:

    掌握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.coloradmin.cn/o/1441424.html

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

相关文章

Elasticsearch:通过 ingest pipeline 对大型文档进行分块

在我之前的文章 “Elasticsearch&#xff1a;使用 LangChain 文档拆分器进行文档分块” 中&#xff0c;我详述了如何通过 LangChain 对大的文档进行分块。那个分块的动作是通过 LangChain 在 Python 中进行实现的。对于使用版权的开发者来说&#xff0c;我们实际上是可以通过 i…

【Fabric.js】监听画布or元素的点击、选中、移动、添加、删除销毁、变形等各事件

在fabric使用过程中&#xff0c;如果想要玩各种花样&#xff0c;那么fabric的事件监听是一定、必须、肯定要掌握&#xff01;&#xff01;&#xff01; 例子就用vue项目组件里的代码&#xff0c;fabric的使用跟vue、react、angular之类的框架都没任何关系&#xff01; 并且本de…

MySQL学习记录——칠 表操作

文章目录 1、了解2、创建和插入1、基本创建和插入2、插入并更新on duplicate3、插入并替换replace 3、Retrieve1、查询select2、条件查询where3、结果排序order by4、限制行数limit 4、更新Update5、删除delete6、去重7、聚合函数&#xff08;5个&#xff09;1、count2、sum3、…

Project2007下载安装教程,保姆级教程,附安装包和工具

前言 Project是一款项目管理软件&#xff0c;不仅可以快速、准确地创建项目计划&#xff0c;而且可以帮助项目经理实现项目进度、成本的控制、分析和预测&#xff0c;使项目工期大大缩短&#xff0c;资源得到有效利用&#xff0c;提高经济效益。软件设计目的在于协助专案经理发…

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

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

高德 API 10009

问题 笔者使用高德地图所提供的API接口&#xff0c;访问接口报错 {"info":"USERKEY_PLAT_NOMATCH","infocode":"10009","status":"0","sec_code_debug":"d41d8cd98f00b204e9800998ecf8427e"…

SolidWorks学习笔记——草图绘制的基本命令

目录 一、进入草图绘制 二、直线命令与删除命令 三、圆弧命令与矩形命令 四、槽口命令以及多边形命令 五、椭圆以及倒角命令 六、草图绘制中的剪裁命令 七、草图中的几何关系 八、草图绘制中的智能尺寸 九、从外部粘贴草图&#xff08;CAD&#xff09; 一、进入草图绘…

基于鲲鹏服务NodeJs安装

准备工作 查看当前环境 uname -a查看鲲鹏云CPU架构 cat /proc/cpuinfo# 查看CPU architecture项&#xff0c;8表示v8&#xff0c;7表示v7下载Node.js NodeJs 选择 Linux Binaries (ARM) ARMv8 wget -c https://nodejs.org/dist/v12.18.3/node-v12.18.3-linux-arm64.tar.xz…

创新指南|生成式AI实验 - 企业快速渐进采用人工智能的科学新方法

生成式人工智能&#xff08;Gen AI&#xff09;正迅速成为各行各业的企业创新焦点。 生成式AI实验对于企业创新而言至关重要&#xff0c;不仅可以帮助企业识别最适合和最有影响的应用场景&#xff0c;还能促进组织沿着生成式 AI 学习曲线前进&#xff0c;建立早期的创新领导者和…

【Java】苍穹外卖 Day02

苍穹外卖-day02 课程内容 新增员工员工分页查询启用禁用员工账号编辑员工导入分类模块功能代码 **功能实现&#xff1a;**员工管理、菜品分类管理。 员工管理效果&#xff1a; 菜品分类管理效果&#xff1a; 1. 新增员工 1.1 需求分析和设计 1.1.1 产品原型 一般在做需…

git rebase # |REBASE 1/1 #rebase in progress; onto

git 代码解决冲突之后会提示rebase in progress; onto 1 执行git rebase --abort 回到没有pull代码之前 2 git pull 3 解决冲突 4 git add . (不需要git commit) 5 git rebase --continue 6 git push

MyBatis之动态代理实现增删改查以及MyBatis-config.xml中读取DB信息文件和SQL中JavaBean别名配置

MyBatis之环境搭建以及实现增删改查 前言实现步骤1. 编写MyBatis-config.xml配置文件2. 编写Mapper.xml文件&#xff08;增删改查SQL文&#xff09;3. 定义PeronMapper接口4. 编写测试类1. 执行步骤2. 代码实例3. 运行log 开发环境构造图总结 前言 上一篇文章&#xff0c;我们…

【leetcode热题100】最大矩形

给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵&#xff0c;找出只包含 1 的最大矩形&#xff0c;并返回其面积。 示例 1&#xff1a; 输入&#xff1a;matrix [["1","0","1","0","0"],["1",&quo…

【教3妹学编程-算法题】LCP 30. 魔塔游戏

3妹&#xff1a;2哥&#xff0c;干嘛呢&#xff0c;一个人闷闷不乐的&#xff0c;在看什么呢。 2哥 : 这不快过年了嘛&#xff0c; 想回家过年给我的小侄子买个礼物&#xff0c;结果他张口说想要个ps5. 那玩意我都没有&#xff0c;他还想要。我看看网上有什么好的礼物适合他的。…

使用npm包js-web-screen-shot做网页截图,可以对截图加文字,箭头等等,类似于微信截图

<template><div class"m-feedback-wrap" :style"{ top: ${feedbackHeight}px }"><div class"m-feedback-icon-wrap"><el-tooltipclass"item"effect"dark"content"内容"placement"left-…

Linux线程库封装

一 MyThread.hpp #pragma once #include<pthread.h> #include<iostream> #include<unistd.h> #include<string> #include<ctime>typedef void (*callback_t)(); static int num 1; //任务和线程绑定 class Thread {static void* Routine(void …

Qt 字符串类应用与常用基本数据类型

目录 操作字符串 查询字符串 Qt 常见数据类型 操作字符串 创建一个控制台项目 &#xff08;1&#xff09;QString提供一个二元的 “” 操作符&#xff0c;主要用于组合两个字符串。QString str1 "Hello World 传递给QString一个 const char* 类型的ASCII字符串 “He…

计算机网络基本知识(一)

文章目录 概要速率带宽、吞吐量带宽吞吐量 时延发送&#xff08;传输&#xff09;时延传播时延排队时延处理时延时延带宽积 利用率 概要 速率、带宽、吞吐量、时延、利用率 速率 记忆要点&#xff1a;10的三次方 记忆要点&#xff1a;2的10次方 带宽、吞吐量 带宽 单位&…

Linux开发:PAM1 介绍

PAM(Pluggable Authentication Modules )是Linux提供的一种通用的认证方式,他可以根据需要动态的加载认证模块,从而减少认证开发的工作量以及提供认证的灵活度。 1.PAM的框架 PAM的框架由一下几个部分构成 1)应用程序,即需要使用认证服务的程序,这些应用程序是使用抽象…

【pip】本地和Anaconda的pip冲突时如何指定安装位置

输入指令&#xff1a; where pip 显示如下&#xff1a; D:\LenovoSoftstore\Anaconda\Scripts\pip.exe C:\python\python3.8\Scripts\pip.exe 可以看到有两个位置的pip&#xff0c;一个Anaconda下的pip&#xff0c;一个是本地的pip。 当我们使用pip安装的时候&#xff0c;系…