程式中,經常需要重複的進行某些動作,這時候,就需要用到"迴圈"。 其中一種方法是 for 迴圈,語法如下:
for(變數初始值;迴圈繼續的條件;變數遞增值){ 程式敘述; }「變數初始值」、「迴圈繼續的條件」、「變數遞增值」這三個部分,必須用分號隔開。 而迴圈中的程式敘述,會依照變數值的變化,被重複的執行。例如,下面這個程式可以印出 1 到 10:#include <stdio.h> int main () { int i; for( i=1 ; i<=10 ; i++ ){ printf("%d\n", i); } return 0; }會跟著迴圈跳動的變數,若沒有其他特殊用途,則習慣上會命名為 i, j, k 等等。 「i++」的意思,與「i=i+1」相同。 第7行的 printf,會因會變數 i 從 1 跑到 10,而印出 1~10 的數字。在上面的範例中,當 i = 10 的迴圈結束後, 會再次執行「i++」,讓 i 的值變成 11,不符合繼續的條件,迴圈因而停止。 此時,若在迴圈外部印出 i 的值,就可以發現是 11:
#include <stdio.h> int main () { int i; for( i=1 ; i<=10 ; i++ ){ printf("in: %d\n", i); } printf("out: %d\n", i); return 0; }如果想要印出不太一樣的數列,可以把迴圈的條件修改一下, 例如若想印出 1, 3, ..., 9,則可改為:for( i=1 ; i<=10 ; i+=2 )若想印出 10, 9, ..., 1,則可改為:for( i=10 ; i>=1 ; i-- )關於「變數初始值」、「迴圈繼續的條件」、「變數遞增值」這三個部分, 可以有零或多個(用逗號隔開)條件和值,不過分號不能省略。:
#include <stdio.h> int main () { int i = 3, j = 5; for( ; i<=10 ; i++, j=j+2 ){ printf("%d %d\n", i, j); } return 0; }我們將前面的範例稍微變更一點點,則可以從 1 加到 100:
#include <stdio.h> int main() { int sum = 0, i; for(i=1;i<=100;i++){ sum = sum + i; } printf("1 加到 100 是 %d\n", sum); return 0; }其中的變數 sum,會依次被加上 1, 2, 3, ..., 100,所以迴圈跑完以後,就可以得到 1 加到 100 的結果。 記得一開始要初始化為 0 (歸零),否則可能得到無法預期的結果 (大部分的編譯器會幫你完成這個動作,但是不能保證)。如果是計算階乘,千萬記得改變一下初始值。以下示範計算 10 的階乘:
#include <stdio.h> int main() { int prod = 1, i; for( i=1 ; i<=10 ; i++ ){ prod = prod * i; } printf("1 乘到 10 是 %d\n", prod); return 0; }如果要計算比較一般化的等差級數和, 則可簡單的把「變數初始值」、「迴圈繼續的條件」、「變數遞增值」改用變數來給值或判斷:
#include <stdio.h> int main() { int sum = 0, i, a1 = 3, an = 101, d = 2; /* 也可以改成讓使用者輸入 */ for( i=a1 ; i<=an ; i+=d ){ /* i += d 與 i = i + d 同意 */ sum = sum + i; } printf("首項 %d,末項 %d,公差 %d 的級數和是 %d\n", a1, an, d, sum); return 0; }當然,也可以用公式計算級數和。尤其是項數多的時候,用公式計算會比迴圈來的有效率。費氏數列也很適合用迴圈來計算, 以下程式可以計算費氏數列第 n (n ≥ 2)項的值:
#include <stdio.h> int main() { int prev1 = 1, prev2 = 0, n, fn, i; printf("請輸入 n 值:"); scanf("%d", &n); for( i=2 ; i<=n ; i++ ){ fn = prev1 + prev2; prev2 = prev1; prev1 = fn; } printf("費氏數列第 %d 項是 %d\n", n, fn); return 0; }迴圈跟條件判斷一樣,也可以是巢狀(一層包一層)的。以下程式使用了兩層的 for 迴圈來輸出九九乘法表:
#include <stdio.h> int main () { int i, j; for( i=1 ; i<=9 ; i++ ){ for(j=1 ; j<=9 ; j++){ printf("%d*%d=%2d ", i, j, i*j); } printf("\n"); } return 0; }這支程式的輸出為:1*1= 1 1*2= 2 1*3= 3 1*4= 4 1*5= 5 1*6= 6 1*7= 7 1*8= 8 1*9= 9 2*1= 2 2*2= 4 2*3= 6 2*4= 8 2*5=10 2*6=12 2*7=14 2*8=16 2*9=18 3*1= 3 3*2= 6 3*3= 9 3*4=12 3*5=15 3*6=18 3*7=21 3*8=24 3*9=27 ......(以下略)Question: 如何改成印直的?使用巢狀迴圈時,要注意內層迴圈的變數必須跟外層不同。 以下是一個會發生問題的範例,內層和外層同時使用了變數 i。 各位可以在執行之前,先預測一下它的效果:
#include <stdio.h> int main () { int i, j; for( i=1 ; i<=5 ; i++ ){ for(i=1 ; i<=3 ; i++){ printf("%d\n", i); } printf("\n"); } return 0; }另外一種迴圈指令是 while,其語法為:
while(條件式){ 程式敘述; }只要條件符合,迴圈就會一直執行。以下程式也會印出 1 到 10,各位可以體會一下 while 與 for 的語法差異:
#include <stdio.h> int main () { int i = 1; while(i<=10){ printf("in: %d\n",i); i++; } printf("out: %d\n",i); return 0; }利用 while 迴圈,很適合觀察「3n+1問題」的數列。這個問題的規則是這樣的:
- 給定一正整數 n
- 當 n 是偶數時:除以 2
- 當 n 是奇數時:乘以 3 再 +1
- 最後會在 4, 2, 1 三者之間循環
所以我們可以利用 while 迴圈,加上 if 進行判斷,寫出下面的程式:#include <stdio.h> int main() { int n = 13; printf("%d ", n); while(n!=1){ if(n%2==0){ n /= 2; } else { n = 3*n + 1; } printf("%d ",n); } printf("\n"); return 0; }與 while 迴圈很相似的是 do...while 迴圈:
do { 程式敘述; } while(條件式);只要條件符合,就跟 while 迴圈一樣,會一直執行。 但 do...while 迴圈在第一次進來執行的時候是無條件的,意思是至少會執行一次。 同樣用印出 1~10 作為範例:#include <stdio.h> int main() { int i=1; do{ printf("in: %d\n",i); i++; } while(i<=10); printf("out: %d\n",i); return 0; }「break;」可以跳出所在的這一層迴圈,「continue;」可以繼續下一層迴圈:
#include <stdio.h> int main() { int i, j; printf("First loop:\n"); for(i=1;i<=5;i++){ if(3==i){ break; } printf("%d ",i); } printf("\n"); printf("Second loop:\n"); for(i=1;i<=5;i++){ if(3==i){ continue; } printf("%d ",i); } printf("\n"); printf("Nested loop:\n"); for(i=1;i<=3;i++){ for(j=1;j<=5;j++){ printf("%d %d\n", i, j); if(i==2){ break; } } } printf("\n"); return 0; }如果熟悉了迴圈的語法,則可以做出一個簡單的終極密碼遊戲。 先來看看虛擬碼(此例之設計為,密碼有可能是上下界之一):
while(1){ /* 無窮迴圈,猜中才能跳出 */ 提示使用者在上下界之間,輸入一個數字 if( 輸入數字恰為密碼 ){ 猜中、break; } else if( 數字<密碼 && 數字≥下界 ){ 下界 ← 數字 + 1; } else if( 數字>密碼 && 數字≤上界 ){ 上界 ← 數字 - 1; } else { 不要來亂; } }C 語言中,把 0 當做「否」,其餘的非 0 值當做「是」, 所以「while(1)」的寫法,會造成無窮迴圈(迴圈停不下來)。 當然,猜中密碼時遊戲就要結束,所以 break 的條件就是猜中密碼。以下是完整程式碼:#include <stdio.h> int main() { int low = 1, high = 100, pwd = 35, guess; while(1){ printf("請在 %d 與 %d 之間猜一數字: ", low, high); scanf(" %d", &guess); if(guess==pwd){ printf("猜中了\n"); break; } else if( guess<pwd && guess>=low ){ low = guess + 1; } else if( guess>pwd && guess<=high){ high = guess - 1; } else { printf("範圍有誤,請重新輸入!\n"); } } return 0; }範例當中的數字是事先寫死的,當然也可以改用亂數產生。往後會提到如何產生亂數。高中學過的勘根定理,也可以用迴圈來實做。 勘根定理告訴我們,如果函數 f 是連續的,且 f(a)*f(b) ≤ 0,則 [a, b] 之間至少有一根。 求根的步驟如下:
- 找一個區間 [a, b],使 f(a) 和 f(b) 異號
- 求 a, b 中點 c,並求 f(c)
- 如果 f(a) 和 f(c) 同號,則取 c 為新左界,否則取 c 為新右界
- 重複 2 和 3,至夠精確為止
面對未知的函數,要很快的猜出適合的 a 和 b,是比較困難的,所以範例中的 a 和 b 是固定值。 以下程式,會計算 x5 - x - 1 = 0 在 (-0.5, 1.5) 之間的某一根:#include <stdio.h> #include <math.h> int main() { double a = -0.5, b = 1.5, c, fa, fb, fc; fa = pow(a, 5.0) - a - 1; fb = pow(b, 5.0) - b - 1; while( fa * fb < 0 ){ c = (a+b)/2; fc = pow(c, 5.0) - c - 1; if( fabs(fc) < 0.000001){ /* 夠小則中止 */ break; } if( fa*fc > 0 ){/* f(a), f(c)同號,以c為新左界 */ a = c; } else { b = c; } } printf("Root: %.4f\n", c); return 0; }