【新书推荐】7.4 多重循环

本节必须掌握的知识点:

        for循环嵌套语句

        示例二十五

        代码分析

        汇编解析

7.4.1 for循环嵌套语句

在我们总结中,语句块这个解释不知道读者是否感到不解,既然语句块里可以做任何事情,那么它的里面就可以再写一个循环语句,我们称为循环嵌套语句。顾名思义,循环语句中再嵌套一个或多个循环语句。

那么我们看下它的语法形式。

for循环嵌套语句

为了使读者更容易理解,我们把嵌套在里面的for循环条件改成,for(表达式4;表达式5;表达式6;语句块2;其中语句块1替换成了for循环语句。

for(表达式1;表达式2;表达式3)

{

//语句块1;

for(表达式4;表达式5;表达式6)

{

语句块2;

}

}

●语法解析:

第一步:执行表达式1,表达式1表示初始化外循环变量;

第二步:执行表达式2,表达式2:终止条件,如果条件表达式为真,则执行循环体内的语句块,否则退出for语句;

第三步:执行循环体内的语句1,语句块1替换成内层for循环语句,执行表达式4,表达式4表示初始化内循环变量;

第四步执行表达式5,表达式5:终止条件,如果条件表达式为真,则执行循环体内的语句块,否则退出内层嵌套for语句;

第五步:执行代码块2;

第六步:执行表达式6后置表达式;

第七步:继续执行下一轮循环,直到表达式5的条件为假,跳出内层for循环语句。

第八步:执行表达式3;

第九步:执行表达式2,如果条件表达式2为真,则执行循环体内的语句块1,否则退出for语句;

……

第N步:继续执行下一轮循环,直到表达式2的条件为假,跳出for循环语句。

执行顺序:表达式1->表达式2->语句块1(表达式4->表达式5->语句块2->表达式6->表达式5->语句块2->表达式6->表达式5->……直到不满足条件跳出内层循环)->表达式3->表达式2->语句块1……一直循环下去,直到到表达式2为假时,停止循环。我们看示例代码二十五来理解循环嵌套for语句的执行流程。

示例代码二十五

7.4.2 示例二十五

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

分析需求:构建一个双重for循环嵌套语句,当i< 3时,重复执行内层for循环语句,当j <= 3时,重复执行内循环的重复语句块。

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

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

       int i;//定义一个int类型的整型局部变量i,并将其初始化为0,作为外循环变量。

       int j;//定义一个int类型的整型局部变量j,并将其初始化为0,作为内循环变量。

       ●第三步:分析算法。

当i< 3时,重复执行内层for循环语句,当j <= 3时,重复执行内循环的重复语句块。

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

       int main(void) {

    定义一个int类型整型循环变量i和j;

    外循环:

表达式1:将循环变量i初始化为0;

表达式2:当i < 3时执行大括号内的内循环for语句块

表达式3:执行完printf语句后,循环变量i加1

    for (i = 0; i < 3; i++){

    调用printf函数打印信息:"\ni = %d\n"          

       内循环:

表达式1:将循环变量j初始化为0;

表达式2:当j <= 3时执行大括号内的内循环for语句块

表达式3:执行完printf语句后,循环变量j加1

    for (i = 0; j < 3; j++){

    调用printf函数打印信息:"j = %d\t"                

}                   

}

调用printf函数打印信息"\n"

system("pause");

    return 0;                                                                                                    

}

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

图7-4 示例二十五for循环嵌套语句

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

/*

   for语句的嵌套

*/

#include <stdio.h>

#include <stdlib.h>

int main(void) {

    int i, j;

    for (i = 0; i < 3; i++)

    {

        printf("\ni = %d\n", i);

        for (j = 0; j <= 3; j++)

        {

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

        }

    }

    printf("\n");

    system("pause");

    return 0;

}

●输出结果:

i = 0

j = 0   j = 1   j = 2   j = 3

i = 1

j = 0   j = 1   j = 2   j = 3

i = 2

j = 0   j = 1   j = 2   j = 3                                 

7.4.3 代码分析

分析执行流程:

第一次执行外层循环:

第一步:执行 int i = 0;

第二步:执行 i<3;0<3条件为真,继续往下执行 ;

第三步:执行printf(“\ni=%d\n”,i);输出 i = 0;

第一次执行内层循环:

第四步:执行内层for循环,j=0;

第五步:执行j<=3,0<3,条件为真,继续往下执行;

第六步:执行printf(“j=%d\t”,j);输出 j = 0;

第七步:执行j++,此时j=0+1,j=1;

第八步:执行j<=3,1<3,条件为真,继续往下执行;

第九步:执行printf(“j=%d\t”,j);输出 j = 1;

第十一步:执行j<=3,2<3,条件为真,继续往下执行;

第十二步:执行printf(“j=%d\t”,j);输出 j =2;

第十三步:执行j++,此时j=2+1,j=3;

第十四步:执行j<=3,3=3,条件为真,继续往下执行;

第十五步:执行printf(“j=%d\t”,j);输出 j =3;

第十六步:执行j++,此时j=3+1,j=4;

第十七步:执行j<=3,4>3,条件为假,跳出内层循环。

第二次执行外层循环:

第十八步:执行i++,i=0+1,i=1;

第二十步:执行i<3;1<3条件为真,继续往下执行,

第二十一步:执行printf(“\ni=%d\n”,i);输出 i =1;

第二次执行内循环:(重复第一次执行内循环做的事情)

第二十二步:执行内层for循环,j=0;

第二十三步:执行j<=3,0<3,条件为真,继续往下执行;

第二十四步:执行printf(“j=%d\t”,j);输出 j = 0;

第二十五步:执行j++,此时j=0+1,j=1;

第二十六步:执行j<=3,1<3,条件为真,继续往下执行;

第二十七步:执行printf(“j=%d\t”,j);输出 j = 1;

第二十八步:执行j++,此时j=1+1,j=2;

第二十九步:执行j<=3,2<3,条件为真,继续往下执行;

第三十步:执行printf(“j=%d\t”,j);输出 j =2;

第三十一步:执行j++,此时j=2+1,j=3;

第三十二步:执行j<=3,3=3,条件为真,继续往下执行;

第三十三步:执行printf(“j=%d\t”,j);输出 j =3;

第三十四步:执行j++,此时j=3+1,j=4;

第三十五步:执行j<=3,4>3,条件为假,跳出内层循环。

第三次执行外层循环:

第三十六步:执行i++,i=1+1,i=2;

第三十七步:执行i<3;2<3条件为真,继续往下执行,

第三十八步:执行printf(“\ni=%d\n”,i);输出 i =2;

第三次执行内循环:(重复第一次执行内循环做的事情)

第三十九步:执行内层for循环,j=0;

第四十步:执行j<=3,0<3,条件为真,继续往下执行;

第四十一步:执行printf(“j=%d\t”,j);输出 j = 0;

第四十二步:执行j++,此时j=0+1,j=1;

第四十三步:执行j<=3,1<3,条件为真,继续往下执行;

第四十四步:执行printf(“j=%d\t”,j);输出 j = 1;

第四十五步:执行j++,此时j=1+1,j=2;

第四十六步:执行j<=3,2<3,条件为真,继续往下执行;

第四十七步:执行printf(“j=%d\t”,j);输出 j =2;

第四十八步:执行j++,此时j=2+1,j=3;

第四十九步:执行j<=3,3=3,条件为真,继续往下执行;

第五十步:执行printf(“j=%d\t”,j);输出 j =3;

第五十一步:执行j++,此时j=3+1,j=4;

第五十二步:执行j<=3,4>3,条件为假,跳出内层循环。

第四次执行外层循环:

第五十三步:执行i++,i=2+1,i=3;

第五十四步:执行i<3;3=3条件为假,跳出外层循环,当然结束外层循环那么内层循环将不会执行。

7.4.4 汇编解析

汇编代码

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

include vcIO.inc

.data

i sdword  ?

j sdword  ?

.const    

szMsg1 db 0dh,0ah,"i = %d",0dh,0ah,0

szMsg2 db "j = %d",09h,0

szMsg3 db 0dh,0ah,0

.code     

start:

       mov i,0

NEXT1:         

       .while i < 3

              invoke printf,offset szMsg1,i

              mov j,0         

NEXT2:

              .while j <= 3

                     invoke printf,offset szMsg2,j             

                     inc sdword ptr j;

                     jmp NEXT2         

              .endw           

              inc sdword ptr i;

              jmp NEXT1         

       .endw           

       ;

       invoke printf,offset szMsg3

       ;     

       invoke _getch

       ret                       

end start

●输出结果:

i = 0

j = 0   j = 1   j = 2   j = 3

i = 1

j = 0   j = 1   j = 2   j = 3

i = 2

j = 0   j = 1   j = 2   j = 3

上述汇编代码中,使用高级汇编伪指令.while替换C语言中的for语句实现双重循环。NEXT1地址标号作为外循环起始地址,NEXT2地址标号作为内循环起始地址。

【注意】内循环开始前,需要将内循环变量j重新初始化为0。

反汇编代码

    int i, j;

    for (i = 0; i < 3; i++);外循环

00E01838  mov         dword ptr [i],0  ;表达式1

    int i, j;

    for (i = 0; i < 3; i++)

00E0183F  jmp         main+3Ah (0E0184Ah

00E01841  mov         eax,dword ptr [i]  

00E01844  add         eax,1                ;表达式3

00E01847  mov         dword ptr [i],eax 

00E0184A  cmp         dword ptr [i],3  ;表达式2

00E0184E  jge         main+7Eh (0E0188Eh;i>=3时,退出外循环

    {

        printf("\ni = %d\n", i);循环语句块2

00E01850  mov         eax,dword ptr [i] 

00E01853  push        eax 

00E01854  push        offset string "\ni = %d\n" (0E07B30h) 

00E01859  call        _printf (0E0104Bh) 

00E0185E  add         esp,8 

        for (j = 0; j <= 3; j++);内循环

00E01861  mov         dword ptr [j],0  ;表达式4

00E01868  jmp         main+63h (0E01873h

00E0186A  mov         eax,dword ptr [j] 

00E0186D  add         eax,1                ;表达式6

00E01870  mov         dword ptr [j],eax 

00E01873  cmp         dword ptr [j],3  ;表达式5

00E01877  jg          main+7Ch (0E0188Ch)  ;j>3时,退出内循环

        {

            printf("j = %d\t", j);循环语句块2

00E01879  mov         eax,dword ptr [j] 

00E0187C  push        eax 

00E0187D  push        offset string "j = %d\t" (0E07B3Ch) 

00E01882  call        _printf (0E0104Bh) 

00E01887  add         esp,8 

        }

00E0188A  jmp         main+5Ah (0E0186Ah;内循环,跳转到表达式6

    }

00E0188C  jmp         main+31h (0E01841h;外循环,跳转到表达式3

    printf("\n");

00E0188E  push        offset string "\n" (0E07B44h) 

00E01893  call        _printf (0E0104Bh) 

00E01898  add         esp,4 

    system("pause");

00E0189B  mov         esi,esp 

    system("pause");

00E0189D  push        offset string "pause" (0E07B48h) 

00E018A2  call        dword ptr [__imp__system (0E0B168h)] 

00E018A8  add         esp,4 

上述反汇编代码验证了for循环嵌套语句的执行流程。请读者参考注释阅读代码,此处不再赘述。

实验五十三: 打印九九乘法表

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

       /*

   for语句双重循环:打印九九乘法表

*/

#include <stdio.h>

#include <stdlib.h>

int main(void) {

    int i, j;

    j = 0;

    for (i = 1; i <= 9; i++)

    {

        for (j = 1; j <= 9; j++)

        {

            printf("%3d ", i * j);

        }

        printf("\n");

    }

    system("pause");

    return 0;

}

       ●输出结果:

       1   2   3   4   5   6   7   8   9

  2   4   6   8  10  12  14  16  18

  3   6   9  12  15  18  21  24  27

  4   8  12  16  20  24  28  32  36

  5  10  15  20  25  30  35  40  45

  6  12  18  24  30  36  42  48  54

  7  14  21  28  35  42  49  56  63

  8  16  24  32  40  48  56  64  72

  9  18  27  36  45  54  63  72  81

请按任意键继续. . .

       上述代码9行*9列的方式在控制台窗口输出九九乘法表。程序使用for语句的双循环结构,循环变量i表示行,循环变量j表示列。循环变量的取值范围为1~9。

实验五十四: 打印直角三角形

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

/*

   for语句双重循环:打印直角三角形

*/

#include <stdio.h>

#include <stdlib.h>

int main(void) {

    int i, j, n;

    int len;

    printf("生成直角在左下方的等腰直角三角形。\n");

    printf("短边:");

    scanf_s("%d", &len);

    for (i = 1; i <= len; i++)//输出行

    {

        for (n = 1; n <= len - i; n++)//输出列' '

        {

            putchar(' ');

        }

        for (j = 1; j <= i; j++)//输出列'*'

        {

            putchar('*');

        }

        printf("\n");//换行

    }

    system("pause");

    return 0;

}

●输出结果:

生成直角在左下方的等腰直角三角形。

短边:8

       *

      **

     ***

    ****

   *****

  ******

 *******

********

       上述代码实现其实非常简单,我们可以把直角三角形看成是一个由空格和*号组成的长方形,只需要建立for语句双循环结构分别循环打印行和列就可以实现了。需要注意的是,在输出列时分别输出len-i个空格和i个*号。

提示

       通常在项目中,我们仅需要双循环结构就可以了。很少需要用到三重及以上的循环结构。即使确有多重循环的需要,也可以将其封装为函数调用的形式实现。我们将在第九章详细介绍函数的知识。

练习

  1. 画一个长方形:

高:3,宽:7

*******

*******

*******

2、生成直角在左下方的等腰直角三角形。

短边:5

*

**

***

****

*****

3、编写一段程序,像右面这样显示所输入整数为边长的正方形。

生成一个正方形

正方形有几层:3

***

***

***

4、显示出一个横向较长的长方形。

读取两个边的边长,以较小的数作为行数,以较大的数作为列数。

一边:7

另一边:3

*******

*******

*******

5、编写一段程序,输入一个整数,像右面这样显示出输入整数层的金字塔形状。

提示;第i行显示(i-1)*2+1个星

金字塔有几层:3

  *

 ***

*****

6、编写一段程序,像右面这样显示出输入整数层的向下的金字塔形状。第i行显示i%10的结果。

金字塔有几层:3

11111

 222

  3

7、使用for语句,输出于下面的图所示的样式。

                            2(1)

                             2(2)

                             2(3) 

  1. 编写一段程序,输出九九乘法表。

                             1

本文摘自编程达人系列教材《汇编的角度——C语言》。

相关推荐

  1. xdoj购票系统(多次循环

    2024-02-12 13:36:01       32 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-02-12 13:36:01       19 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-02-12 13:36:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-02-12 13:36:01       20 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-02-12 13:36:01       20 阅读

热门阅读

  1. 求小数的某一位(c++题解)

    2024-02-12 13:36:01       31 阅读
  2. H5/CSS 笔试面试考题(61-70)

    2024-02-12 13:36:01       34 阅读
  3. VSCode官方历史版本下载

    2024-02-12 13:36:01       38 阅读
  4. Leetcode 3035. Maximum Palindromes After Operations

    2024-02-12 13:36:01       37 阅读
  5. Ubuntu搭建计算集群

    2024-02-12 13:36:01       41 阅读
  6. 装箱问题+宠物小精灵之收服+数字组合——01背包

    2024-02-12 13:36:01       29 阅读
  7. 龙芯安装Docker

    2024-02-12 13:36:01       28 阅读
  8. 学习数据结构和算法的第7天

    2024-02-12 13:36:01       33 阅读
  9. JVM调优的一些常用技术

    2024-02-12 13:36:01       28 阅读