實 習 內 容 |
|
實
|
while 迴圈及 for 迴圈 1. 計次迴圈 (Counting loop) 2. 以特定輸入資料結束的迴圈 (Sentinel-controlled loop) 3. 什麼時候該用迴圈??? |
1 |
計次迴圈: 下面這個 while 迴圈程式片段由鍵盤讀入固定筆數的資料, 計算總薪資並列印出來:count_emp = 0; /* no employees processed yet */ while (count_emp < 7) /* test value of count_emp */ { printf("Hours> "); scanf("%d", &hours); printf("Rate> "); scanf("%lf", &rate); pay = hours * rate; printf("Pay is $%6.2f\n", pay); count_emp = count_emp + 1; /* increment count_emp */ } printf("\nAll employees processed\n"); 上面程式中哪一個變數是迴圈控制變數 (loop controlling variable)? 這個迴圈總共執行幾次? 如果你在迴圈一開始的地方加上 printf("count_emp=%d\n", count_emp); 的敘述, 會看到什麼數值印出來呢? 1, 2, 3, 4, ..., 7 還是 0, 1, 2, ..., 6 請將上面迴圈改以 for 語法完成: for (count_emp=0; count_emp<7; count_emp++) { ... } |
2 |
以特定輸入資料結束的迴圈 (sentinel-controlled loop): 下面這一段程式由鍵盤讀入使用者輸入的多個成績資料, 使用者最後會輸入一個特定的結束資料 -99 (預期成績資料不會有這種數值) 來結束這個迴圈, 程式會計算出成績總和:/* Compute the sum of a list of exam scores. */ #include <stdio.h> #include <stdlib.h> #define SENTINEL -99 int main(void) { int sum = 0, /* sum of scores input so far */ score; /* current input score */ /* Accumulate sum of all scores. */ printf("Enter first score (or %d to quit)> ", SENTINEL); scanf("%d", &score); /* Get first score. */ while (score != SENTINEL) { sum += score; printf("Enter next score (%d to quit)> ", SENTINEL); scanf("%d", &score); /* Get next score. */ } printf("\nSum of exam scores is %d\n", sum); system("pause"); return(0); } 請拷貝上述程式至 dev C++ 編譯, 執行 請修改上面的程式, 將鍵盤輸入改為由 scores.dat 檔案輸入, 並且改為計算成績的平均值
|
3 |
到底什麼時候該用迴圈? 在課堂上解釋過 for 迴圈、while 迴圈、和 do-while 迴圈的基本語法以後, 知道每一個迴圈都會包括四個部份: 下面我們來討論幾個時機點 1. 當你需要重複做相同的事情很多次時例如: 也就是如果不用迴圈你需要寫下面的程式 scanf("%d", &x); printf("%d\n", x*x*x); scanf("%d", &x); printf("%d\n", x*x*x); scanf("%d", &x); printf("%d\n", x*x*x); scanf("%d", &x); printf("%d\n", x*x*x); scanf("%d", &x); printf("%d\n", x*x*x); printf("hello world\n"); printf("hello world\n"); printf("hello world\n"); printf("hello world\n"); printf("hello world\n"); x = x + y; x = x + y; x = x + y; x = x + y; x = x + y; 顯然你可以用迴圈來讓你的程式不會重複出現一樣的程式碼, 如下: for (i=0; i<5; i++) { scanf("%d", &x); printf("%d\n", x*x*x); } for (i=0; i<5; i++) printf("hello world\n"); for (i=0; i<5; i++) x = x + y; 上面第三個例子比較沒有道理, 你會說為什麼不用 x = x + 5 * y; 就好了, 這是因為我們還沒有用陣列的原因, 讓 y 這個變數重複用了 5 次, 如果是 y[i] 的話就比較有道理了 重點是: 上面你看到一模一樣的程式碼重複出現多次, 所以使用迴圈, 有的時候甚至只出現兩次, 我們還是會用迴圈, 因為我們有一個基本原則: 程式裡一模一樣的敘述不會出現兩次, 否則
2. 當你需要重複做類似的事情很多次時
也就是如果不用迴圈你需要寫下面的程式 scanf("%d%d", &a, &b); printf("%d\n", a+b); scanf("%d%d", &a, &b); printf("%d\n", a-b); scanf("%d%d", &a, &b); printf("%d\n", a*b); scanf("%d%d", &a, &b); printf("%d\n", a/b); 這時候你也許覺得上面這樣子寫沒什麼不對的, 每一列都不太一樣啊! 迴圈主體裡面沒有『都一樣』啊??? 既然不太一樣那不就不能用迴圈了?! 其實上面這些 概念上還是可以看成是重複的程式碼, 它們重複的部份是: 那麼不太一樣的地方該怎麼辦呢??? 如果是日常生活的話, 可能就有一些小規則, 比如說如果坐基隆市公車要付多少錢, 坐基隆客運由某站到某站要付多少錢, 坐台汽由某站到某站要付多少錢.... 那就是要判斷了.... if ..... 就出現了, 如果比較規律化的話, 可以運用變數、陣列、迴圈、或是函式的語法再進一步簡化, 例如: for (i=0; i<20; i++) { scanf("%d%d", &a, &b); if (i%4==0) 上面第三個寫法是很好的, 不同的地方完全用變數的運算來取代, 很簡潔!! 第四個寫法一定是不好的, 用了 26 個變數, 還用很大的一個 switch 敘述, 比原來的 26 列程式還多, 通常這時就是會使用陣列變數的時候了, 如果資料不是放在 a, b, c, ..., z 的變數裡, 而是放在 data[0], data[1], ..., data[25] 這 26 個變數裡面, 程式就可以簡化成 for (i=0; i<26; i++) x = x + data[i]; 這時候所有不同的地方完全用變數 i 以及陣列變數 data[i] 的存取來取代, 很簡潔!! 要變成 100 個或是 1000 個變數也很容易 第一個和第二個的寫法勉強可以, 要進一步簡化的話可以用 函式 或是 函式指標的陣列 來完成, 類似下面的作法 void printArithmetic(int type, int a, int b); for (i=0; i<20; i++) { scanf("%d%d", &a, &b); printArithmetic(i%4, a, b); } void printArithmetic(int type, int a, int b) { if (type==0) 現在是迴圈內的東西變成完全一樣了, 在概念上簡化了, 但是程式碼其實幾乎是一樣的, 另外一種方式是 int add(int a, int b) { return a+b; } int sub(int a, int b) { return a-b; } int mul(int a, int b) { return a*b; } int div(int a, int b) { return a/b; } typedef int (*FP)(int, int); FP op[] = {add, sub, mul, div}; for (i=0; i<20; i++) { scanf("%d%d", &a, &b); printf("%d\n",(*op[i%4])(a,b)); } 這個例子因為用到函式指標以及陣列, 比較難懂一些, 可以以後再回來仔細看, 目前你就只要注意到: 迴圈內的東西變成完全一樣了, 不一樣的地方用 op 陣列和 變數 i 來處理 接下來再看一個例子, 上星期的實習需要一個程式印出 On the first day of Christmas my true love sent to me: A Partridge in a Pear Tree On the second day of Christmas my true love sent to me: 2 Turtle Doves and a Partridge in a Pear Tree On the third day of Christmas my true love sent to me: 3 French Hens 2 Turtle Doves and a Partridge in a Pear Tree 這樣也有看到重複性的東西 @@ 有啊! 每一段都是 On the .... 是有重複, 但是每一段裡面好像變化還蠻大的 人很厲害 (至少受過訓練的工程師是這樣), 人都很會抽象化, 也都會故意把不太一樣的東西看成是一樣的, 你看下面的東西會覺得重複性相當大了吧! On the xxx day of Christmas my true love sent to me: . On the xxx day of Christmas my true love sent to me: .. On the xxx day of Christmas my true love sent to me: ... 有一種我很會的感覺吧!! 這就是我都會忘記每一個人名字的原因啊, 都是同學嘛 const char *numbers[] = {"first", "second", "third"}; for (i=0; i<3; i++) printf("On the %s day of Christmas\nmy true love sent to me:\n", numbers[i]); 那個 ... 就是我故意假裝沒看到的東西, 我還用 . 代表一列, .. 代表兩列, ... 代表三列呢, ... 個數不太一樣, 看下面的程式怎樣印這些 ... const char *numbers[] = {"first", "second", "third"}; for (i=0; i<3; i++) { printf("On the %s day of Christmas\nmy true love sent to me:\n", numbers[i]); for (j=0; j<i+1; j++) printf("."); printf("\n"); } 好, 玩夠了, 接下來要把它們變成不一樣的東西 On the first day of Christmas my true love sent to me: 1 On the second day of Christmas my true love sent to me: 21 On the third day of Christmas my true love sent to me: 321 這也容易 const char *numbers[] = {"first", "second", "third"}; for (i=0; i<3; i++) { printf("On the %s day of Christmas\nmy true love sent to me:\n", numbers[i]); for (j=0; j<i+1; j++) printf("%d", i+1-j); printf("\n"); } 接下來換成字串 On the first day of Christmas my true love sent to me: A Partridge On the second day of Christmas my true love sent to me: 2 Turtle A Partridge On the third day of Christmas my true love sent to me: 3 French 2 Turtle A Partridge 稍微簡化了一點 const char *numbers[] = {"first", "second", "third"}; const char *lines[] = {"A Partridge", "2 Turtle", "3 French"}; for (i=0; i<3; i++) { printf("On the %s day of Christmas\nmy true love sent to me:\n", numbers[i]); for (j=0; j<i+1; j++) printf("%s\n", lines[i-j]); printf("\n"); } 用陣列 lines 和 變數 i, j 來印出不同的字串, 剩下的就是處理 i 為 0 時其實要印 "A Partridge", i 大於 0 時要印 "and a Partridge", 你知道不同時候要有不同的表現就是用 if 來判斷, if (i==0) ... 還有最後的換列 printf("\n"); 也需要一點處理, 因為並不是在每一段最後都要換列, 又是有一點點不同的地方.... 用 if 來判斷吧, if (i<2) ... |
4 |
迴圈應用練習: 請撰寫 for 迴圈, 如果使用者輸入 7, 在螢幕上顯示下面七列 *** 如果使用者輸入 3, 在螢幕上顯示下面三列 *** #include <stdio.h> #include <stdlib.h> int main(void) { int nlines; int i, j; do { printf("Please input an odd line number: "); scanf("%d", &nlines); } while (nlines%2==0); for (i=0; i<nlines/2+1; i++) { for (j=0; j<i+1; j++) printf("***"); printf("\n"); } for (i=nlines/2+1; i<nlines; i++) { for (j=0; j<nlines-i; j++) printf("***"); printf("\n"); } system("pause"); return 0; }請注意: 在迴圈內容不太多的情況下, 迴圈控制變數 i, j, k, ... 是在程式裡唯一不要求你仔細命名的變數, 常常在程式裡也會重複使用, 但是第二次使用時會避免使用先前殘留下來的數值, i, j, k, 這種變數沒有適當命名的變數是避免用來在兩段程式之間傳遞資料的 |