目錄表

國立屏東大學 資訊工程學系 程式設計(一)

10. 迴圈Loop


Chicago的捷運系統自1892年起開始營運(不過它還不是世界上最早的捷運系統,London的捷運自1863年起就開始營運了),目前共有八條路線,大部份路線為高架或地面路線。Chicago的downtown稱為路普區,這是因為當捷運進入市區後,會以環狀的方式繞行一圈才離開,請見figure 1。路普的英文是Loop,意思就是繞圈。

 資料來源:http://chicago.straightdope.comFig. 1

在C語言中,也有所謂的Loop,我們稱之為迴圈,用以重複地執行特定的程式碼。請參考figure 2,一個迴圈通常使用一組大括號將一些程式敘述包裹起來,並且反複地執行,直到特定的條件成立或不成立為止。判斷是否繼續執行的地方,可以在迴圈區塊的開頭處或是結束處,視所使用的loop敘述而定。本章將C語言所支援的loop敘述分別加以介紹。

典型的loop執行動線Fig. 2

10.1 while迴圈

while敘述的語法如下:

while (controlling_expression) statements

while敘述先判斷controlling_expression的值,若為true則一直執行後續的statement,直到controlling_expression的值為false時才結束。

<note important>

while迴圈可包含一行或一行以上的敘述

</note>

所以,while迴圈中的敘述可能會被執行0次到無限多次,視其controlling_expression的值而定。以下是一些例子:

// 計算1+2+3+...+10的結果
int i=1, sum=0;
 
//執行十次
while(i<=10)
{
   sum+=i;
   i++;
}
printf("sum of 1 to 10 is %d.\n", sum);

// 印出介於1到100間可以被7整除的數字
int i=1;
 
while(i<=100)
{
   if(i%7==0)
      printf("%d ", i);
   i++;
}

<note important>C語言使用數值0表示false,其它非0的數值皆為true!</note>

// 反覆執行直到使用者輸入'q'為止
int quit=0;
char c;
 
while(!quit)
{
   // do something
   ...
   printf("continue?(y/n)");
   scanf("%c", &c);
   if(c=='n')
      quit=1;
}

// 反覆執行直到使用者輸入'q'為止
int quit=0;
char c;
 
while(1)
{
   // do something
   ...
   if(expression)
      break;      //直到特定條件成立時,使用break跳離
}

10.1.1 無窮迴圈(infinite loop)

有時,不小心設定while的controlling_expression,其結果會導致程式永遠無法結束,因為不論在各種情況下,controlling_expression永遠為true。我們將這種情況稱為無窮迴圈(infinite loop),例如:

// 反覆執行直到使用者輸入'q'為止
int quit=0;
char c;
 
while(i=100)      //這裡將i==100寫成了i=100
{
   // do something
   ...
   if(expression)
      i=100;      //直到特定條件成立時,將i設定為100
}

<note important> 若真的遇到此種情況,在Linux/Unix系統請使用Ctrl+C將程式跳離,然後使用ps aux指令查看程式的PID,再以kill -9 PID指令將程式的執行中止掉。 </note>


10.2 do迴圈

do敘述的語法如下:

do statements while (controlling_expression);

do迴圈與while迴圈類似,不同之處在於其判斷是否繼續之處位於exiting point。do敘述執行statements,然後才判斷接在while後面的controlling_expression的值,若為true則繼續回到do迴圈開頭處再次執行;若controlling_expression的值為false時,do迴圈才結束。相較於while迴圈,do迴圈內含的statements至少會被執行一次。以下是一些例子:

i=10;
 
do
{
     printf("%d\n", i);
     i--; 
} while (i>0);

i=10;
 
do
{
     printf("%d\n", i);
} while (--i>0);

i=10;
 
do
{
     printf("%d\n", i);
} while (i-- > 0 );


10.3 for迴圈

for敘述的語法如下:

for ( expression1; expression2; expression3 ) statements

其中expression1、expression2與expression3,分別是用以定義迴圈的初始條件、中止條件與更新(update)的處理,說明如下:

我們可以用while的語法,來將for的語法改寫如下:

expression1;
while ( expression2)
{
   statements
   expression3;
}

以下是一些例子:

int i,sum=0;
 
for(i=1;i<=10;i++)
{
   sum+=i;
}
printf("sum=%d\n", sum);

在expression1與expression3中也可以用','同時指定多個運算式,例如:

int i,sum;
 
for(i=1, sum=0;i<=10;i++)
{
   sum+=i;
}
printf("sum=%d\n", sum);

expression1-3也可以被省略,例如:

int i=0;
 
for( ; i<10;i++)
   printf("i=%d.\n", i);

10.4 巢狀迴圈(nested loop)

一個迴圈內如含有另一個迴圈,則稱之為,巢狀迴圈(nested loop)。每一層的迴圈可以是for、while或do其中一個,以下我們僅以for迴圈為例,其它的組合您可以自行學習。

//印出1!+2!+3! + ... + 10!
int i,j,temp,sum=0;
 
for(i=1;i<=10;i++)
{
   temp=0;
 
   for(j=1; j<=i; j++)
   {
      temp*=j;
   }
 
   sum += temp;
}
 
printf("sum=%d.\n", sum);

請思考以下問題:

//印出1!+2!+3! + ... + 10!
int i,j,temp=1,sum=0;
 
for(i=1;i<=10;i++)
{
   temp*=i;
   sum += temp;
}
 
printf("sum=%d.\n", sum);

10.5 從迴圈中跳離

除了使用迴圈的controlling_expression來控制迴圈的執行外,我們還可以使用break、continue與goto敘述來改變程式的動線,使其可以跳離迴圈所屬的程式區塊。

10.5.1 break敘述

break在迴圈中一旦被執行,則在此次迴圈執行過程中剩下還未執行的敘述就會被跳過不執行,並且結束迴圈的執行。當迴圈的中止條件不在開頭或結尾時,break敘述就便得很有用處,例如:

//反覆要求使用者輸入一個整數,並且將其累加,直到使用者輸入0為止
 
int n, sum=0;
 
for(;;)
{
   printf("Please input a number (0 for quit):");
   scanf("%d", &n);
   if(n==0)
      break;
   sum+=n;
}
printf("sum=%d.\n", sum);

10.5.2 continue敘述

continue則和break相反,它並不會結束迴圈的執行,而是省略當次執行時未完成的程式碼,直接執行迴圈的下一回合。

//反覆要求使用者輸入一個整數,並且將其累加,直到使用者輸入0為止,但輸入值若為負數則加以忽略
 
int n, sum=0;
 
for(;;)
{
   printf("Please input a number (0 for quit):");
   scanf("%d", &n);
   if(n==0)
      break;
   if(n<0)
      continue;
   sum+=n;
   // continue敘述使程式碼跳到了這裡
}
printf("sum=%d.\n", sum);

10.5.3 goto敘述

C語言還提供另一種無條件的跳躍敘述 – goto敘述。我們可以在程式碼中的特定位置標記一些label,其方法為在某行以標記名稱後接冒號的方式來定義,爾後需要改變程式碼執行動線時,則使用goto 標記名稱;的方式即可完成。請參考以下的範例:

//反覆要求使用者輸入一個整數,並且將其累加,直到使用者輸入0為止
 
   int n, sum=0;
 
   for(;;)
   {
      printf("Please input a number (0 for quit):");
      scanf("%d", &n);
      if(n==0)
         goto done;
      sum+=n;
   }
 
done:
   printf("sum=%d.\n", sum);

goto敘述不一定要配合迴圈的使用,例如:

h goto.c

#include <stdio.h>
 
int main()
{
char cmd;
 
begin:
 
   scanf("%c", &cmd);
 
   if(cmd != 'q')
      goto begin;
 
   printf("exit\n");
}

這個程式讓使用者不斷地輸入一個字元,直到其輸入字元為'q'時才結束程式。其中第7行定義了一個名為begin的標記,在第11行的if敘述若條件成立時則使用goto敘述跳躍到begin標記處。

<note tip> 許多程式設計師一直在爭論是否該在程式碼中使用goto,正反兩面的意見都值得參考。我覺得如果您覺得好用就用吧?只是每次使用時也順便想一想:同樣的功能如果不使用goto可以做到嗎?以免以後你不用goto就不會寫程式!我所認識的程式設計師裡面,兩種人都有,不過反對使用goto的人,通常完全容不下在程式中使用goto。如果你擔心以後工作上的主管或同事不喜歡你寫的含有goto的程式,那你最好用與不用都會寫,這樣就沒問題了!不要使用goto </note>