c語言有哪幾種循環結構?
使用循環可以多次重復地執行多條語句,這里的“多條語句”稱為循環體。在C語言中,可以使用三種循環,分別是:while、do...while和for。還有go to語句也可達到循環目的,但不常用。在這些語句中,循環體被重復執行的次數由循環條件控制,稱為控制表達式(controlling expression)。這是一個標量類型的表達式,也就是說,它屬于一個算術表達式或指針表達式。如果控制表達式的值不等于 0,循環條件為 true,反之,循環條件為 false。語句 break 和 continue 用于在一次循環還未執行完時,跳轉出循環或返回到循環頭部。while 循環
只要控制表達式為 true,while 循環就會反復地執行語句:
while (表達式)語句
while 表達式是頂部驅動(top-driven)的循環:先計算循環條件(也就是控制表達式)。如果為 true,就執行循環體,然后再次計算控制表達式。如果控制表達式為 false,程序跳過循環體,而去執行循環體后面的語句。從語法上講,循環體只有一條語句組成。如果需要執行多條語句時,可以使用語句塊把它們組合在一起。例 1 展示了一個簡單的 while 循環,從控制臺讀入多個浮點數,并把它們累加。例 1 展示了一個簡單的 while 循環,從控制臺讀入多個浮點數,并把它們累加?!纠?】一個 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 %.2f\n", 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 循環初始化數組內每個元素的過程?!纠?】用 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()的一個版本,循環體僅為一條簡單的語句,而不是一個語句塊。因為在循環體執行之后才計算循環條件,所以字符串終止符'\0'也會被復制?!纠?】函數 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++] != '\0' ); // 如果剛剛復制的是'\0',則結束循環
return s1;
}