C語言回圈結構(while迴圈,for迴圈,do…while迴圈)

2020-07-16 10:04:20
使用迴圈可以多次重複地執行多條語句,這裡的“多條語句”稱為迴圈體在C語言中,可以使用三種迴圈,分別是:while、do...while和for。

在這些語句中,迴圈體被重複執行的次數由迴圈條件控制,稱為控制表示式(controlling expression)。這是一個標量型別的表示式,也就是說,它屬於一個算術表示式或指標表示式。如果控制表示式的值不等於 0,迴圈條件為 true,反之,迴圈條件為 false。

語句 break 和 continue 用於在一次迴圈還未執行完時,跳轉出迴圈或返回到回圈頭部。

while 迴圈

只要控制表示式為 true,while 迴圈就會反復地執行語句:

while (表示式)語句


while 表示式是頂部驅動(top-driven)的迴圈:先計算回圈條件(也就是控制表示式)。如果為 true,就執行迴圈體,然後再次計算控制表示式。如果控制表示式為 false,程式跳過迴圈體,而去執行迴圈體後面的語句。

從語法上講,迴圈體只有一條語句組成。如果需要執行多條語句時,可以使用語句塊把它們組合在一起。例 1 展示了一個簡單的 while 迴圈,從控制台讀入多個浮點數,並把它們累加。

例 1 展示了一個簡單的 while 迴圈,從控制台讀入多個浮點數,並把它們累加。

【例1】一個 while 迴圈
/* 從鍵盤輸入數位,然後輸出它們的平均值
* -------------------------------------- */
#include <stdio.h>
int main()
{
   double x = 0.0, sum = 0.0;
   int count = 0;
   printf( "t--- Calculate Averages ---n" );
   printf( "nEnter some numbers:n"
           "(Type a letter to end your input)n" );
   while ( scanf( "%lf", &x ) == 1 )
   {
      sum += x;
      ++count;
   }
   if ( count == 0 )
     printf( "No input data!n" );
   else
     printf( "The average of your numbers is %.2fn", sum/count );
   return 0;
}

在例 1 中,只要使用者輸入一個小數,下面的控制表示式即為 true:
scanf( "%lf", &x ) == 1

然而,只要函數 scanf()無法將字串輸入轉換成浮點數(例如,當使用者鍵入字母 q 時),則 scanf()返回值 0(如果是遇到輸入流的尾端或發生錯誤時,則返回值 -1,表示 EOF)。這時,迴圈條件為 false,程式將會跳出迴圈,繼續執行迴圈體後面的 if 語句。

for 迴圈

和 while 一樣,for 迴圈也是一個頂部驅動的迴圈,但是它包含了更多的迴圈邏輯,如下所示:

for ([表示式1];[表示式2];[表示式3])
    語句


在一個典型的 for 迴圈中,在迴圈體頂部,下述三個動作需要執行:

(1) 表示式 1:初始化
只計算一次。在計算控制表示式之前,先計算一次表示式 1,以進行必要的初始化,後面不再計算它。

(2) 表示式 2:控制表示式
每輪迴圈前都要計算控制表示式,以判斷是否需要繼續本輪迴圈。當控制表示式的結果為 false,結束回圈。

(3) 表示式 3:調節器
調節器(例如計數器自增)在每輪迴圈結束後且表示式 2 計算前執行。即,在執行了調節器後,執行表示式 2,以進行判斷。

例 2 展示了使用一個 for 迴圈初始化陣列內每個元素的過程。

【例2】用 for 迴圈初始化陣列
#define ARR_LENGTH 1000
/* ... */
long arr[ARR_LENGTH];
int i;
for ( i = 0; i < ARR_LENGTH; ++i )
    arr[i] = 2*i;

for 迴圈頭部中的三個表示式可以省略一個或多個。這意味著 for 迴圈頭部最短的形式是:
for ( ; ; )

如果沒有控制表示式,則表示迴圈條件始終是 true,也就是說,這定義了一個死迴圈

下面所示的 for 迴圈,既沒有初始化表示式,也沒有調節器表示式,它與 while(表示式)語句含義是等效的:
for ( ;表示式; )

事實上,每個 for 迴圈都可以被改寫成 while 迴圈,反之亦然。例如,例 2 的 for 迴圈可完全等效為下面的 while 迴圈:
i = 0;                             // 初始化計數器
while ( i < ARR_LENGTH )     // 迴圈條件
{
    arr[i] = 2*i;
    ++i;                        // 遞增計數器
}

一般來說,當迴圈內有計數器或索引變數需要被初始化,並且在每次回圈時需要調整它們的值時,最好使用 for 迴圈,而不是 while 迴圈。

在ANSI C99中,也可以使用宣告來替代表示式1。在這種情況下,被宣告變數的作用域被限制在 for 迴圈範圍內。例如:
for ( int i = 0; i < ARR_LENGTH; ++i )
    arr[i] = 2*i;

變數 i 被宣告在該 for 迴圈中(與例 2 不同)for 迴圈結束之後,變數 i 將不會再存在。

逗號運算子常常被用在 for 迴圈頭部,以在表示式 1 中實現多個初始化操作,或者在表示式 3 對每個變數做調整操作。例如,函數 strReverse()使用兩個索引變數以儲存字串中字元的次序:
void strReverse( char* str)
{
  char ch;
  for ( size_t i = 0, j = strlen(str)-1; i < j; ++i, --j )
    ch = str[i], str[i] = str[j], str[j] = ch;
}

借助於逗號運算子,可以在只允許出現一個表示式的地方,計算多個表示式。

do...while 迴圈

do...while 迴圈是一種底部驅動的迴圈

do 語句 while (表示式);


在控制表示式被第一次計算之前,迴圈體語句會首先被執行一次。與 while 和 for 迴圈不同,do...while 迴圈會確保迴圈體語句至少執行一次。如果控制表示式的值為 true,那麼另一次迴圈就會繼續;如果是 false,則迴圈結束。

在例 3 中,讀入與執行命令的函數至少會被呼叫一次。當使用者離開選單系統,函數 getCommand()將返回常數 END 的值。

【例3】do···while
// 讀入和執行所選的選單命令
// --------------------------------------------
int getCommand( void );
void performCommand( int cmd );
#define END 0
/* ... */
do
{
  int command = getCommand();   // 詢問選單系統
  performCommand( command );    // 執行所選的選單命令
} while ( command != END );

例 4 展示了標準庫函數 strcpy()的一個版本,迴圈體僅為一條簡單的語句,而不是一個語句塊。因為在迴圈體執行之後才計算回圈條件,所以字串終止符''也會被複製。

【例4】函數 strcpy()使用 do...while
// 將字串2複製到字串1
// ----------------------------
char *strcpy( char* restrict s1, const char* restrict s2 )
{
  int i = 0;
  do
     s1[i] = s2[i];               // 迴圈體:複製每一個字元
  while ( s2[i++] != '' );      // 如果剛剛複製的是'',則結束回圈
  return s1;
}