第五章 循环控制


§5.1 概述 §5.2 goto语句
§5.3 while语句 §5.4 do-while语句
§5.5 for语句 §5.6 循环的嵌套
§5.7 几种循环的比较 §5.8 break语句和continue语句
§5.9 程序举例  

 

§5.1 概述

循环:反复执行称为“循环体”的程序段。

循环控制常用于数学迭代、对象遍历等问题的求解,几乎所有实用程序都包含循环。特别是在现代多媒体处理程序(图像、声音、通讯)中,循环更是必不可少。Intel公司为了加快循环程序的执行,在CPU硬件中加入多媒体扩展指令MMX(Multi-Media-eXtension );AMD在CPU中加入3D Now!指令。

循环结构是结构化程序三种基本结构之一。(顺序结构、分支结构)。

根据开始循环的初始条件和结束循环的条件不同,C语言中用如下语句实现循环

1、用goto语句和if语句构成循环。

2、用while语句。

3、用do-while语句。

4、用for语句。


§5.2 goto语句

一般形式: goto 语句标号
    作用: 无条件转向“语句标号”处执行。
“语句标号”是一个标识符,它表示程序指令的地址。

 

goto语句不符合结构化程序设计准则,因为无条件转向使程序结构无规律、可读性差。一般应避免使用goto语句,但如果能大大提高程序的执行效率,也可以使用。

[例5.1] 用if语句和goto语句构成循环,求

main()
{  
  int i,sum=0;
  i = 1;
loop: if (i <= 100)
   { sum = sum + i;
     i++;
     goto loop;
   }
  printf("%d",sum);
}  

§5.3 while语句

一般形式:

while(表达式) 语句

 

作用:实现“当型”循环。当“表达式”非0(真)时,执行“语句”。“语句”是被循环执行的程序,称为“循环体”。

特点:先判“表达式(条件)”。

[例5.2]

流程图:

main()
{  
  int i,sum=0;
  i = 1;
  whie (i <= 100)
   {
      sum = sum + i;
      i++;
   }
  printf("%d",sum);
}  

注意:

1、注意给出循环的初始条件,如本例中“sum=0、i=1”。

2、循环体包含一个以上的语句时,用大括号括起来,形成复合语句。

3、循环体中必须有使循环趋于结束的语句,否则程序进入“死循环”(不结束)。


§5.4 do-while语句

一般形式:

do 语句

while (表达式)

特点:“直到型”循环结构。先执行一次“语句”,判“表达式”,当“表达式”非0,再执行“语句”,直到“表达式”为0,循环结束。

[例5.3] 用do-while语句求

main()
{  
  int i,sum=0;
  i = 1;
  do
  { sum = sum + i;
   i++;
  }
  while(i<=100);
  printf("%d",sum);
}  

注意:

1、上面的流程图中循环条件是“当i≤100时循环”,N-S图中的条件是“循环直到i>100”,这两者是等同的。

2、同一个问题,既可以用while循环处理,也可以用do-while循环处理。

do-while处理,图5.3(p68) while处理,图5.5(p69)

在一般情况下,用while和do-while语句解决同一问题时,若二者的循环体部分是一样的,它们的结果也一样。但当while后面的“表达式”一开始就为“假”时,两种循环的结果不同。这是因为此时while循环的循环不被执行,而do-while循环的循环体被执行一次。

[例5.4] 求i+(i+1)+(i+2)+....+10,其中,i由键盘输入。(用while和do-while两种语句分别编程序)。

while循环程序
do-while循环程序
main() main()
{ int sum=0,i; { int sum=0,i;
  scanf("%d",&i);   scanf("%d",&i);
  while(i <= 10)   do
  { sum = sum + i;   { sum = sum + i;
    i++;     i++;
  }   }while(i<= 10);
  printf("%d",sum);   printf("%d",sum);
} }

§5.5 for语句

for语句常用于循环次数已知的循环控制,也可以灵活用于其他循环控制。

一般形式:

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

执行过程:

(1)求表达式1;

(2)求表达式2,若为“真”,执行“语句”;若为假,转第(5)步。

(3)求表达式3。

(4)转第(2)步。

(5)执行for语句下面的语句。

for语句中: “表达式1”设置循环初始条件
  “表达式2”判别循环条件
  “表达式3”修改循环条件

例、

for(i=1;i<=100;i++) sum = sum + i;

这里,循环条件由变量i设定,变量i称为“循环变量”。

“表达式1”,i=1,  循环初始条件。
“表达式2”,i<=100, 循环条件。
“表达式3”,i++,  修改循环条件。

这是for语句的典型用法:已知循环次数。(本例100次)。

上述for语句也可以用如下while语句表示:

i = 1;
while (i <= 100)
{ sum = sum + i;
 i++;
}

for语句使用非常灵活,可以省略“表达式1”、“表达式2”、“表达式3”中的几个或全部表达式。

1、for语句省略“表达式1”。“表达式1”的作用是设定循环初始条件,“表达式1”省略后,应在for语句前面设置循环初始条件。例、

for(;i<=100;i++)sum = sum + i;

/* 注意,“表达式1”后面的分号不能省略 */

2、for语句中,如果省略“表达式2(循环条件)”,不判别循环条件,认为循环循环条件始终为“真”,循环将无终止地进行下去。

for(i=1;□;i++) sum = sum + i;
相当于:
i = 1;
while (1)
{
sum = sum + i;
i++;
}

3、“表达式3(修改循环条件)”也可以省略,但程序应在循环体(“语句”)中修改循环条件,以保证循环能正常结束。例、

for (sum=0,i=1;i<=100;□)
{ sum = sum + i;
  i++;
}  

4、省略“表达式1”和“表达式3”,只有“表达式2”。例、

for(;i<=100;) 相当于 while (i<=100)
{ sum = sum + i; { sum = sum + i;
i++;} i++;}

5、“表达式1”、“表达式2”、“表达式3”均省略。例、

for(;;)语句 while(1) 语句

这是一种简单的死循环形式。

6、for语句的其他变形。

例1、for(sum=0;i<=100;i++) sum = sum + i;
例2、for(sum=0,i=1;i<=100;i++) sum = sum + i;
例3、for(i=0,j=100;i<=j;i++,j--) k = i + j;
例4、for(i=0;(c=getchar()) != '\n';i += c);
例4的执行情况:

§5.6 循环的嵌套

循环嵌套:一个循环(称为“外循环”)的循环体内包含另一个循环(称为“内循环”)。内循环中还可以包含循环,形成多层循环。(循环嵌套的层数理论上无限制)。

三种循环(while循环、do-while循环、for循环)可以互相嵌套。例、

(1)

(2)

while() do

 {┆

 { ┆
    while()     do
     {...}       {...}
 }      while();
   }
    while();

(3)

(4)

for(;;) while()
 { ┆  { ┆
   for(;;)     do
     {...}      {....}
  }      while();
    ┆
   }
(5)

(6)

for(;;) do
 { ┆  {
   while()    ┆
    {....}     for(;;)
   ┆      {....} 
}    ┆
   }
   while();

多重循环的使用与单一循环完全相同,但应特别注意内、外层循环条件的变化。


§5.7 几种循环的比较

1、四种循环(while、do-while、for、goto)可以互相替换,但应尽量少用goto。

2、循环条件:while、do-while在whie后面指定;for循环在“表达式3”中指定。

3、循环初始条件:while、do-while在循环前指定;for循环在“表达式1”中指定。

4、判循环条件的时机:while、for循环先判循环条件,后执行;do-while循环先执行,后判循环条件。

5、while、do-while、for循环均可用break语句跳出循环(结束循环),用continue语句提前结束本次循环体的执行。


§5.8 break语句和continue语句

一、break语句

作用:跳出所在的多分支switch语句,跳出所在的while、do-while、for循环语句(提前结束循环)。

例、

for (r=1;r<=10;r++)
{ area = pi*r*r;
  if (area > 100) break;
  printf("%f",aera);
}  
r aera
1 3.14
2 12.57
3 28.27
4 50.27
5 78.54
6 113.10
7 153.94
8 201.06
9 254.47
10 314.16

 

二、continue语句

作用:提前结束本次循环体的执行,接着进行下一次循环条件的判别。

[例5.5] 把100~200之间不能被3整除的数输出。

main ()
{ int n;
  for (n=100; n<=200; n++)
  { if (n%3 == 0)
      continue;
     printf("%d",n);
  }
}  

三、break语句和continue语句的区别

while (表达式1) while (表达式1)
{  ┇ {  ┇
  if (表达式2) break;   if (表达式2) continue;
   ┇    ┇
} }
break语句跳出循环 continue语句结束本次循环体的执行,进入下一次循环

§5.9 程序举例

[例5.6] 用以下公式计算л的值,直到最后一项的绝对值小于1E-6为止。

算法分析:

1、每项的分母,等于前一项分母加2,用n=n+2实现,n的初值为1。

2、每项的符号交替变化,用 s = -s实现,s的初值为+1(第一项为正)。

3、根据1和2,每一项的值 t = s/n,第一项的值为1。

#include "math.h"
main()
{
int s;
float n,t,pi;
t = 1; pi = 0; n = 1.0; s = 1;
while((fabs(t)) >= 1E-6)
{ pi = pi + t;
 n = n + 2;
 s = -s;
 t = s/n;
}
pi = pi * 4;
printf("pi=%10.6f\n",pi);
}

运行结果:pi=3.141397

[例5.7] 求Fibonacci数列:1,1,2,3,5,8,....的前40个数,即:

F1 = 1 (n = 1)
F2 = 1 (n = 2)
Fn = Fn-1 + Fn-2 (n≥3)

算法:

即:把40个数分为每2个一组,每组中的两个数的计算方法为:

f1 = f2 + f1
f2 = f1 + f2

N-S流程图:

程序:

main ()
{  
  long int f1,f2; /* 长整型数 */
  int i;
  f1 = 1; f2 = 1; /* 已知数列的前两个初值 */
  for (i=1; i<=20; i++)
  {
  printf("%12ld %12ld ",f1,f2); /* 输出长整型数 */
  if (i%2 == 0) printf("\n"); /* 控制输出格式 */
  f1 = f2 + f1;
  f2 = f1 + f2;
  }
}  

[例5.8] 输入一个数m,判其是否为“素数”。

素数(prime):又称质数,是大于1的整数,除了能被自身和1整除外,不能被其它正整数整除。

算法:

程序:

#include "math.h"
main ()
{  
  int m,i,k;
  scanf("%d",&m); /* 输入一个整数m */
  k = sqrt(m);
  for(i=2;i<=k;i++)
     if (m%i == 0) break;
  if (i > k+1) printf("%d 是素数\n",m);
  else         printf("%d 不是素数\n",m);
}  

[例5.9] 求100~200间的全部素数。

算法:与上例类似。

程序:

#include "math.h"
main ()
{  
  int m,k,i,n=0;/* n用于累计素数的个数 */
  for(m=101; m<=200; m=m+2)
   { if (n%10 == 0) printf("\n");
     k = sqrt(m);
     for(i=2; i<=k; i++)
        if (m%i == 0) break;
     if (i >= k+1) { printf("%d ",m); n = n+1;}
   }
}  

[例5.10]

译密码。为使报文保密,往往按一定规律将其转换为密码,收报人再按约定的规律将其译为原文。设加密规律为:将字母变成其后的第四个字母,如,A变为E,a变为e。

输入一行字符,要求将其变为密码。

 

算法:

1、当输入字符不是“回车”时,执行密码转换。

2、仅转换A~Z、a~z。

3、转换规则:c=c+4,当c=Z~Z+4范围,或c>z时,c=c-26。

程序:

#include "stdio.h"
main ()
{  
   char c;
   while ((c=getchar()) != '\n')
   {
     if ((c>='a' && c<='z') || (c>='A' && c<='Z'))
      {
      c = c + 4;
      if (c>'Z' && c<='Z'+4 || c>'z') c = c - 26;
      }
    printf("%c",c);
   }
}  

[小结] 从以上几个例子可以看到,程序设计中的关键环节有:

1、算法。如求π值的算法、求Fibonicci数列的算法、验证素数的算法、字符的ASCII码间的关系。

算法分析是程序设计中的第一个步骤,也是最重要的步骤。

2、框图。根据算法的要求,列出程序实现的步骤。

框图是保证程序正确性的重要手段,它可以避免程序分支错误或分支遗漏。复杂的算法必须画出框图。

3、程序设计环境。如操作系统的特征、键盘输入的特点(如,仅在按回车键后输入的字符才进入程序缓冲区)、开发系统环境(如#include的使用)等。

4、程序设计的方法(结构化、面向对象)和风格(如适当的缩进)。

5、语言。注意语法规定。如while、do-while、for语句的执行流程和特点,break、continue语句的作用等。

程序 = 算法 + 数据结构 + 程序设计方法 + 语言工具和环境


本章要求

要求:

1、初步熟悉用计算机解决问题的思路。

2、掌握while、do-while、for语句的特点和使用方法。

3、掌握break、continue语句的用法。

4、熟悉一些常见问题的算法及其C语言实现。