BBS水木清华站∶精华区

发信人: ax.bbs@bbs.ee.nthu.edu.tw. (athena), 信区: test 
标  题: 星星流讲座 0020 
发信站: ☆清华电机☆ (Tue May 23 11:20:45 1995) 
 
 
第 4 讲 之 5            基本的流程控制 
                        Topic: for loop (1) 
 
我们前面讨论了 while 和 do-while 的回圈,为什麽叫回圈呢?因为在条件 
成立的时候会一直执行重复的程式区块,所以我们叫它回路或回圈。许多回 
圈在执行的时候是以执行的次数做为条件的,比方说: 
 
        i = 0; 
        while (i < 10) 
        { 
            i++; 
            /* 回圈的剩馀部分,但是不会用到 i,i 只是个计次用的变数 */ 
        } 
 
这个时候我们就可以利用 for 回圈来简化上面的程式: 
 
        for (i = 0; i < 10; i++) 
        { 
            /* 回圈 */ 
        } 
 
for 的用法是这样的: 
 
                for (i = 0; i < 10; i++) 
                     □       ↑       □ 
             计次用变数的   回圈执行    计次用变数 
                初始值      条件        每次值的变化 
 
在做进一步的深入探讨之前,请你写作一个九九乘法表的程式,它的输出和小 
学生垫板後面的相同。 
 
for 回圈最有意思的是计次变数初始值、回圈执行条件及计次变数的变化都可以不 
给,例如: 
 
        for ( ; i > 10; i--)    /* 前面已给过 i 的初值了,所以回圈不必再给 */ 
        for ( ; i > 10; )       /* 回圈中会不规则的变动 i,把 for 当成 while */ 
                                /*   来用,这是因为有人不会用 while :) */ 
        for ( ; ; )             /* 永不停止的回圈 (无穷回圈 infinite loop) */ 
 
以上是最常见的三种情形,其他的情形除非你有特别巧妙的设计,否则该用 while 
的时候还是用 while 来做比较清晰易懂。 
 
/* shellsort.c */ 
#include <stdio.h> 
 
void shellsort (int v[], int n)         /* v[]: array to sort */ 
{                                       /* n: # elements in array */ 
    int gap, i, j, temp; 
 
    for (gap = n / 2; gap > 0; gap /= 2) 
    { 
        printf ("shell sort gap %d\n", gap); 
        for (i = gap; i < n; i++) 
        { 
            printf ("shell sort level %d\n", i); 
            for (j = i - gap; j >= 0 && v[j] > v[j + gap]; j -= gap) 
            { 
                temp = v[j]; 
                v[j] = v[j + gap]; 
                v[j + gap] = temp; 
            } 
        } 
    } 

 
上面的程式是欣赏用的,我们的目的并不在讲 shell sort,而是要和各位谈谈如何 
写出「乾净」的程式码。首先请看到上面程式里的大括号都是上下对齐的,大括号 
内的东西向内缩四格,为什麽要这样做呢?看看以下错误的示□你就知道了: 
 
        for (i = 0; i < 10; i++) { 
                /* .... */ 
        } 
 
第一个不好的习惯是上下的大括号不对齐,像 vi 或 jove 这种编辑器会自动替你 
match 括号,提醒你是否有括号不对称的情形,这当然是很好用的工具。但是如果 
我们现在用的是像 PE2  这种不会替你对括号的编辑器,而你自己又不把括号对齐 
的话,那麽可以预见的是你常常会得到这个错误讯息: 
 
        parse error at end of input 
 
第二个不好的习惯是程式码不缩排,例如: 
 
    for(gap=n/2;gap>0;gap/=2) 
    { 
    printf("shell sort gap %d\n",gap); 
    for(i=gap;i<n;i++) 
    { 
    printf("shell sort level %d\n",i); 
    for(j=i-gap;j>=0 && v[j]>v[j+gap];j-=gap) 
    { 
    temp=v[j]; 
    v[j]=v[j+gap]; 
    v[j+gap]=temp; 
    } 
    } 
    } 
 
所有的码挤成一堆,一点层次感也没有,层次感除了美观之外,它其实有重要的功 
用,在像上面的多重回圈里我们要很用力的看才能看出它在干什麽,而不能如前面 
的 shellsort.c 那麽一目了然。程式码易读的最大好处是缩短除错的时间,减少 
维护程式的成本。 
 
至於运算元 (operator) 前後的空白,例如 i = j + 4; 等等,笔者个人是模仿 
Quick BASIC 的风格,如果是单元运算元 (unitary operator) 就不加空白,如: 
i++; ,二元运算元 (binary operator) 则前後加空白,如:i = j;。左小括号 ( 
前面一定加空白,逗号 , 後面也一定加空白。在 C 语言圣经 K&R 的版本里他们分 
的更细,函数的左小括号前头没有空白,非函数的左小括号前头有空白,例如: 
 
        printf("Hello, world!\n");      /* 函数 */ 
        for (i = 1; i < 10; i++) 
 
笔者因为很喜欢按大大的 space 键听它叩叩的声音,所以左括号前一律加空白 :) 
初学者常常因为懒惰而吃掉不少空白,套句补习班常用的广告词:今日不做,明日 
後悔。别因一时的懒惰种下明日的苦果,什麽苦果?等你程式写到上千行你就知道了。 
 
-- 
本文原作者为徐振家,原作刊载於星星神教总坛 ☆清华电机☆ test 板。 
你可以以电子文件的形式将本文自由流传於台湾学术网路,但必须包含此版权声明。 
原作者依中华民国著作权法之规定,享有本文之著作权,请勿抄袭以免触法。 
未经授权任何人不得以任何形式对本文做任何修改及商业上之应用。 
其他网路的转载或其他用途的应用,请先知会作者,并取得其同意。 
对本文有任何疑问或意见请 mail 给 ax.bbs@bbs.ee.nthu.edu.tw,谢谢。 
 
 

BBS水木清华站∶精华区