使用迴圈可以多次重複地執行多條語句,這裡的“多條語句”稱為
迴圈體。
在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;
}