实例讲解 C 语言的循环结构

类别:编程语言 点击:0 评论:0 推荐:

  这一讲开始之前,我们需要准备一个函数。这个函数的作用就是把一个百分制成绩转换成等级制。转换的过程我已经在讲解分支结构的时候详细阐述了,现在仅提供函数如下:

  /* 准备 grade.h */
  char grade(int score) {
   switch (score / 10) {
    case 10: case 9:
        return 'A';
    case 8:
        return 'B';
    case 7:
        return 'C';
    case 6:
        return 'D';
    case 5: case 4: case 3:
    case 2: case 1: case 0:
        return 'E';
    default:
        return 0;
   }
  }

  在讲解分支结构时提出的实例都只能解决一个成绩的情况。假如需要将 5 个人的成绩进行转换,最简单的办法如下:

  /* 例1 */
  #include "grade.h"
  #include
  void main() {
   int n;
   printf("请输入成绩: ");
   scanf("%d", &n);
   printf("等级为: %c", grade(n));
   printf("请输入成绩: ");
   scanf("%d", &n);
   printf("等级为: %c", grade(n));
   printf("请输入成绩: ");
   scanf("%d", &n);
   printf("等级为: %c", grade(n));
   printf("请输入成绩: ");
   scanf("%d", &n);
   printf("等级为: %c", grade(n));
   printf("请输入成绩: ");
   scanf("%d", &n);
   printf("等级为: %c", grade(n));
  }

  例1 的结构非常简单易懂,但是书写起来只有一个感觉--烦!同样的三句话,居然重复了 5 次。如果这个班的人数不止 5 人,而是数十人的话,……天啊!简直想都不敢想!

  C 语言当然不会笨得来一点方便都不给,这个"方便",就是循环结构。循环结构的目的就是减少重复代码,减轻程序员的负担。而其形式,在 C 语言中有三种:for 循环、while 循环和 do-while 循环。正面分别介绍如下:

  for 循环的基本格式是 for (语句1; 逻辑表达式1; 语句2) {语句组1},大括号包括其中的语句组1 也可以是一条语句。其执行过程如下:先执行语句1,然后判断逻辑表达式1。如果逻辑表达式1 的值为"真(非0)",则执行语句组1,否则结束循环。在没结束循环的情况下,执行了语句组1 之后,执行语句2。然后再对逻辑表达式1 进行判断,再……,如此循环直到逻辑表达式1 为"假(0)"时为止。于是,例1 可以改写如下:

  /* 例2 */
  #include "grade.h"
  #include
  void main() {
   int n, i;
   for (i = 0; i < 5; i++) {
    printf("请输入成绩: ");
    scanf("%d", &n);
    printf("等级为: %c", grade(n));
   }
  }

  嘿,这么简洁?!知道循环结构的便利之处了吧。例2 中 i 从 0 到 4,共执行了 5 次循环体。当然,也可以跟据个人的习惯,将例2 中的 for 语句改写为:

  for (i = 1; i <= 5; i++) {...}

  这样或许更容易理解,但我不推荐这样做,因为 C 语言中的数组下标是以 0 开始的,采用例1 中的 for 语句更容易在循环体中读写数组元素。就上例,如果我们要把所有成绩输入完成之后再逐一将其等级打印出来,就需要用到数组:

  /* 例3 */
  #include "grade.h"
  #include

  #define N 5

  void main() {
   int n[N], i;
   for (i = 0; i < N; i++) {
    printf("请输入成绩: ");
    scanf("%d", &n[i]);
   }
   for (i = 0; i < N; i++) {
    printf("第 %d 个成绩的等级为: %c", i, grade(n[i]));
   }
  }

  例3 中,如果 i 从 1 到 N 循环的话,读写数组元素时就应该使用 n[i - 1] 而不是 n[i]。那么每执行一次循环体就会多一次减法运算,在一个循环 N 次的循环中,就会多进行 N 次减法运算,大大降低了程序效率。

  C 语言是一种灵活的语言。它的 for 循环也不是一成不变,必须按照它的基本格式书写。暂时卖个关子,先看看从例3 修改过来的例4:

  /* 例4 */
  #include "grade.h"
  #include

  #define N 5

  void main() {
   int n[N], i = 0;
   for (; i < N; ) {
    printf("请输入成绩: ");
    scanf("%d", &n[i++]);
   }
   for (i = 0; ; i++) {
    if (i == N) {
     break;
    }
   printf("第 %d 个成绩的等级为: %c", i, grade(n[i]));
  }
  }

  是不是很奇怪,例4 中的两个 for 循环中与上面两个例子的 for 循环相比,都少用了一些语句,怎么回事?且听我慢慢道来:

  第一个 for 循环中,少了 i = 0 和 i++ 两句。其实仔细一看,这两句也没少。i = 0 已经在给 i 赋初值的时候就实现了,而 i++ 是在 scnaf 语句中顺便实现的。所以,虽然没有 i = 0 一句,但循环开始之前 i 的值已经是 0 了;虽然没有 i++ 一句,但循环体中实际也改变了 i 的值。

  第二个 for 循环中少的只是那一句判断。而正是由于少了这一句判断,for 循环便不能自已结束。如果我在循环体中也不采取措施结束循环的话,这个循环将一直不停的执行下去,形成死循环。于是,我在循环体中对 i 进行判断,当它等于 N的时候执行一个 break 语句,跳出循环,填补了 for 语句中没有逻辑表达式的缺陷。

  甚至,一个 for 语句就可以写成 for (; ; ) {...},这样一个 for 语句,简单的说,就是一个死循环。

  还有一点需要说明,就是 break 语句。这个语句在讲解 switch 分支结构的时候就已经见到过了。它除了能用于 switch 分枝结构之外,还能用于所有的三种循环结构。其作用就是两个字--"跳出"。switch 分枝结构中,它用于跳出整个 switch 语句;而在循环结构中,它自然是用于跳出循环,执行它之后,循环体中所有其它语句都不会再执行,整个循环就此中断。

  学会了 for 循环,虽然可以简化不少代码,但它似乎只能解决循环次数固定的情况。如果人数不固定,又该怎么办?比如规定如下:输入若干 0 至 100 的成绩,如果成绩不在此范围,则表式结束。请看例5,例6:

  /* 例5 */
  #include "grade.h"
  #include
  void main() {
    int n;
    printf("请输入成绩: ");
    scanf("%d", &n);
    while (grade(n) != 0) {
     printf("等级为: %c", grade(n));
     printf("请输入成绩: ");
     scanf("%d", &n);
    }
   }

  /* 例6 */
  #include "grade.h"
  #include
  void main() {
   int n;
   do {
    printf("请输入成绩: ");
    scanf("%d", &n);
    if (grade(n) != 0) {
     printf("等级为: %c", grade(n));
   }
  } while (grade(n) != 0);
  }

  例5 和例6 分别使用了 while 循环和 do-while 循环结构。两种循环结构都是在 while 后的逻辑表达式为真时执行循环体,为假时结束循环。二者的不同在于:while 循环是先判断,再执行循环体;而 do-while 循环而是先执行循环体后再作判断。因此,使用 do-while 循环至少要执行一次循环体。至于循环的执行过程,就请读者自己分析了。

  例6 中对于同一个 n,至少要执行两次 grade(n),大大降低了程序的效率。虽然可以用一个 char 型变量来解决这个问题,但我不想这样作。于是又有如下方式的改写:

  /* 例7 */
  #include "grade.h"
  #include
  void main() {
   int n;
   do {
    printf("请输入成绩: ");
    scanf("%d", &n);
    if (grade(n) == 0) {
     break;
    }
   printf("等级为: %c", grade(n));
   } while (1);
  }

  例7 中 while 语句的逻辑表达示值始终是真(1),所以这个循环也就是一个死循环,必须在循环体中用 break 语句跳出。用一个 if 语句判断跳出的时机,这也是很好理解的,就不多说了。但是看看下面的例8,可能就不是那么明白了。

  /* 例8 */
  void main() {
  int n;
  do {
   printf("请输入成绩: ");
   scanf("%d", &n);
   if (grade(n) == 0) {
    continue;
   }
   printf("等级为: %c", grade(n));
  } while (grade(n) != 0);
  }

  例8 的和例6 的区别主要就在于一个 continue 语句。这个语句可是循环结构所特有的,其作用与 break 语句相比,即有相似之处,也有相对之处。执行了 continue 语句之后,循环体中 continue 以下的语句将不再在这次循环中执行,但循环并不中断,而是开始下一次循环。

  如例8 中,满足 grade(n) == 0 的条件后,执行 continue 语句。然后 printf 语句被跳过,直接到 while 语句判断是否结束循环,如果不满足结束循环的条件,那么将会要求输入下一个成绩。不过例8 中,只要能执行到 continue 语句,while 后的条件就一定为假,循环结束。例8 和例7 的区别就在于,例8 是正常结束,而例7 是被中断。

  break 和 continue 两个语句在 C 语言的循环结构中有着举足轻重的作用。虽然使用巧妙的结构化程序手段可以避免使用这两个语句,但这两个语句的确能使程序结构更加简单明了。所以,只要能用上它们的地方,我极力推荐使用它们。

  三种循环结构都说完了,但我还要强调 C 语言的灵活性。虽然循环结构有三种形式,但只使用其中仍意一种都能达到目的。例5 和例6 就展示了使用 while 和 do-while 两种形式完成同要的任务。至于 for 循环,前面说它"似乎只能解决循环次数固定的情况",这"似乎"二字并非笔误。它乍看只能解决循环次数固定的情况,但仔细一想,它也的确能解决循环次数不固定的情况。如例5 例6 用 for 循环的形式分别可以改写为:

  /* 例9 */
  #include "grade.h"
  #include
  void main() {
  int n;
  printf("请输入成绩: ");
  scanf("%d", &n);
  for (; grade(n) != 0; ) {
   printf("等级为: %c", grade(n));
   printf("请输入成绩: ");
   scanf("%d", &n);
  }
  }

  /* 例10 */
  #include "grade.h"
  #include
  void main() {
  int n;
  int b = 1;
  for (; b; ) {
   printf("请输入成绩: ");
   scanf("%d", &n);
   if (grade(n) != 0) {
    printf("等级为: %c", grade(n));
   } else {
    b = 0;
   }
  }
  }


  看看例9 和例5,例10 和例6,是不是有异曲同工之妙?其实 C 语言的循环结构远远不止这些变形,只要你细心思考,一定还会发现更多"变形妙用"。哈哈哈哈,一吐为快,心中舒服多了。

-=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=-
             /\
  __________/LB\___   OUTINN
 /  _[]_   /____\  \
/_________/| () |\__\ http://outinn.yeah.net/
 |  ____ /-| __ |-\|  Welcome to visit OUTINN!
 |__|==|___| || |__|
 -=--=--=- |_||_| =-  Fancy, [email protected]

本文地址:http://com.8s8s.com/it/it30143.htm