關於 C 語言 for、while、do-while 三種迴圈的選用時機,下列敘述何者正確?
選項 A 正確(★ 本題標準答案)
當迴圈次數在執行前就已知時,for 迴圈把初始化、條件、更新集中寫在同一行,通常最直覺也最精簡。
選項 B 錯誤
while 迴圈幾乎可以達成與 for 迴圈相同的效果(只要把初始化、條件、更新分開寫),兩者在功能上是可以互相轉換的。
選項 C 錯誤
三種迴圈在效能上並沒有本質差異,並不存在「do-while 一定最快」的規則。
選項 D 錯誤
次數不確定時,while 也是非常常見且合適的選擇,並非只能用 do-while。
關於 for、while、do-while 三種迴圈的「執行流程本質」,下列敘述何者正確?
選項 A 錯誤
這個描述剛好說反了:for 與 while 都是先檢查條件才執行主體,只有 do-while 才是先執行一次主體。
選項 B 正確(★ 本題標準答案)
for 與 while 都會先檢查條件,條件不成立就完全不執行主體;do-while 則保證主體至少先執行一次,才進行條件檢查,這是三者本質上的關鍵差異。
選項 C 錯誤
三種迴圈「先判斷或先執行」的規則並不相同,do-while 與另外兩者存在真正的行為差異,不只是語法不同。
選項 D 錯誤
do-while 的條件判斷式其實是寫在主體「後面」(`do { ... } while(條件);`),不是最前面。
執行後輸出結果為何?
1 #include <stdio.h>
2 int main(void) {
3 int sum = 0;
4 for (int i = 1; i <= 5; i++) {
5 sum += i;
6 }
7 printf("%d\n", sum);
8 return 0;
9 }選項 A 錯誤
10 不是 1 到 5 的總和,只是把部分數字加總後的錯誤結果。
選項 B 錯誤
5 只是迴圈結束時 i 最後接近的數值,不是 sum 累加的結果。
選項 C 正確(★ 本題標準答案)
迴圈從 i=1 執行到 i=5,sum 依序累加 1+2+3+4+5,結果為 15。
選項 D 錯誤
20 並不符合 1 加到 5 的總和,可能是誤算成 1 到 5 之外的範圍。
關於此程式的執行順序與輸出,下列敘述何者正確?
1 #include <stdio.h>
2 int main(void) {
3 int i;
4 for (i = 0; i < 3; i++) {
5 printf("Loop: i=%d\n", i);
6 }
7 printf("After loop: i=%d\n", i);
8 return 0;
9 }選項 A 錯誤
迴圈結束時 i 的值是「讓條件判斷為假」的那個值,也就是 3,並不是最後一次執行主體時的 2;i=2 執行完主體後,for 的更新部分還會再讓 i 變成 3,才去檢查條件並結束迴圈。
選項 B 錯誤
當 i=3 時,條件 i<3 已經為假,迴圈主體不會再執行,所以不會印出 "Loop: i=3",只會執行 3 次主體。
選項 C 錯誤
此程式的 i 是在行號 3(for 迴圈外)宣告的一般變數,並非在 for 括號內宣告,因此離開迴圈後仍然存在、可以正常使用,不會產生編譯錯誤。
選項 D 正確(★ 本題標準答案)
迴圈執行 3 次主體(i=0,1,2),每次執行完主體後 for 的更新部分都會讓 i 遞增;當 i 遞增到 3 時,條件 i<3 為假而結束迴圈,此時 i 已經是 3,因此行號 7 印出的是 i=3。
此 for 迴圈的初始化與更新部分,使用逗號運算子同時操作兩個變數 i 與 j。執行後輸出結果為何?
1 #include <stdio.h>
2 int main(void) {
3 int sum = 0;
4 for (int i = 0, j = 10; i < 5; i++, j--) {
5 sum += (j - i);
6 }
7 printf("%d\n", sum);
8 return 0;
9 }選項 A 正確(★ 本題標準答案)
五次迭代中 (j-i) 依序為 10、8、6、4、2,總和為 10+8+6+4+2=30。
選項 B 錯誤
20 不符合逐輪 (j-i) 的正確累加結果,可能是漏算或多算了某一輪。
選項 C 錯誤
25 同樣不符合逐輪計算出的正確總和。
選項 D 錯誤
for 迴圈的初始化與更新部分完全可以用逗號運算子同時操作多個變數,這是合法且常見的寫法,不會造成編譯錯誤。
執行後總共會印出幾行?分別是哪一種迴圈印出的?
1 #include <stdio.h>
2 int main(void) {
3 int x = 10;
4 while (x < 5) {
5 printf("while: x=%d\n", x);
6 x++;
7 }
8 int y = 10;
9 do {
10 printf("do-while: y=%d\n", y);
11 y++;
12 } while (y < 5);
13 return 0;
14 }選項 A 錯誤
while 迴圈確實因為條件一開始不成立而完全不執行,但 do-while 迴圈的主體一定會先執行一次,不會什麼都不印。
選項 B 正確(★ 本題標準答案)
while 迴圈在進入前就檢查 x<5(不成立),因此主體完全不會執行;do-while 迴圈則保證先執行一次主體,才檢查 y<5,因此會印出一行 "do-while: y=10",之後條件才變成不成立而結束。
選項 C 錯誤
while 迴圈的主體完全不會被執行,因此不會印出任何一行,只有 do-while 才會印出一行。
選項 D 錯誤
x 與 y 在各自的迴圈主體中都有 x++ 或 y++ 的遞增動作,且 do-while 只會執行一次就因條件不成立而結束,不會是無窮迴圈。
n 的初始值是 100,並不滿足 n<0 這個條件。執行後 count 印出的值是多少?
1 #include <stdio.h>
2 int main(void) {
3 int count = 0;
4 int n = 100;
5 do {
6 count++;
7 } while (n < 0);
8 printf("%d\n", count);
9 return 0;
10 }選項 A 錯誤
do-while 迴圈的主體一定會先執行一次,不論條件在檢查時是真是假,所以 count 不會是 0。
選項 B 錯誤
count 只會在主體被執行的次數增加,這裡主體只執行了一次,不會累加到 100。
選項 C 正確(★ 本題標準答案)
do-while 保證主體至少執行一次:count 先變成 1;接著檢查 n<0(100<0,為假),迴圈結束,因此 count 印出 1。
選項 D 錯誤
迴圈只執行一次主體後,條件 n<0 就為假,迴圈會正常結束,不會是無窮迴圈。
關於 while 與 do-while 迴圈的比較,下列敘述何者正確?
選項 A 錯誤
這個描述剛好說反了:while 的條件寫在主體「前面」,do-while 的條件才是寫在主體「後面」。
選項 B 錯誤
這只適用於 while;do-while 即使條件一開始就不成立,主體仍然會先被執行一次(如第 6、7 題所示)。
選項 C 錯誤
do-while 結尾的 `while(條件)` 之後必須加上分號,這是語法規定,省略會造成編譯錯誤。
選項 D 正確(★ 本題標準答案)
這正是 while 與 do-while 最核心的差異:條件一開始就不成立時,while 完全不執行主體,do-while 仍會先執行一次,才因為條件不成立而不再繼續。
執行後輸出結果為何?
1 #include <stdio.h>
2 int main(void) {
3 for (int i = 1; i <= 10; i++) {
4 if (i == 4)
5 break;
6 printf("%d ", i);
7 }
8 printf("\n");
9 return 0;
10 }選項 A 正確(★ 本題標準答案)
i 依序為 1、2、3 時都會印出;當 i=4 時,if 條件成立,break 會立刻跳出整個迴圈,因此 4 不會被印出,也不會有後續的數字。
選項 B 錯誤
break 發生在印出 4 之前,因此 4 不會被印出,不是「1 2 3 4」。
選項 C 錯誤
break 會在 i=4 時就讓迴圈提前結束,不會繼續執行到 i=10。
選項 D 錯誤
i=1、2、3 這三次迭代在 break 發生之前都已經印出過數字,不會什麼都不印。
執行後輸出結果為何?
1 #include <stdio.h>
2 int main(void) {
3 for (int i = 1; i <= 6; i++) {
4 if (i % 2 == 0)
5 continue;
6 printf("%d ", i);
7 }
8 printf("\n");
9 return 0;
10 }選項 A 錯誤
i 為偶數時(2、4、6)會被 continue 跳過印出的動作,因此不會全部都印出。
選項 B 正確(★ 本題標準答案)
當 i 是偶數(i%2==0)時,continue 會跳過本次剩餘的程式碼(也就是 printf),直接進入下一輪;因此只有奇數 1、3、5 會被印出。
選項 C 錯誤
偶數 2、4、6 正是被 continue 跳過的數字,不會被印出;印出的其實是奇數。
選項 D 錯誤
continue 只會跳過「本次」迴圈剩餘的程式碼、進入下一輪,並不會結束整個迴圈,這與 break 不同。
關於此巢狀迴圈的執行結果,下列敘述何者正確?
1 #include <stdio.h>
2 int main(void) {
3 for (int i = 1; i <= 2; i++) {
4 for (int j = 1; j <= 3; j++) {
5 if (j == 2)
6 break;
7 printf("i=%d,j=%d\n", i, j);
8 }
9 }
10 return 0;
11 }選項 A 錯誤
break 只會跳出它所在的那一層(內層 j 迴圈),並不會連外層 i 迴圈也一起結束,因此外層還會繼續跑第二輪。
選項 B 錯誤
break 確實會真正跳出迴圈,並不只是跳過該次的 printf;這裡是跳出內層 j 迴圈。
選項 C 正確(★ 本題標準答案)
j=2 時 break 只會跳出最靠近它的內層 j 迴圈,外層 i 迴圈完全不受影響、會繼續執行下一輪;i=1 時內層只印出 j=1,i=2 時內層同樣只印出 j=1,總共兩行。
選項 D 錯誤
break 會直接跳出內層迴圈,並不會讓它繼續往下執行到 j=3,所以 j=3 的情況不會被印出。
執行後 count 印出的值是多少?
1 #include <stdio.h>
2 int main(void) {
3 int count = 0;
4 for (int i = 1; i <= 4; i++) {
5 for (int j = 1; j <= 3; j++) {
6 count++;
7 }
8 }
9 printf("%d\n", count);
10 return 0;
11 }選項 A 錯誤
4 只是外層迴圈的執行次數,並不是巢狀迴圈總共的執行次數。
選項 B 錯誤
3 只是內層迴圈單獨一輪的執行次數,並不是總次數。
選項 C 錯誤
7 是 4 與 3 相加的結果,但巢狀迴圈的總執行次數應該是相乘,不是相加。
選項 D 正確(★ 本題標準答案)
外層迴圈執行 4 次,每次外層迭代內層都會完整執行 3 次,總執行次數是 4×3=12。
執行後 count 印出的值是多少?
1 #include <stdio.h>
2 int main(void) {
3 int count = 0;
4 for (int i = 1; i <= 3; i++) {
5 for (int j = 1; j <= 5; j++) {
6 if (j == 3)
7 break;
8 count++;
9 }
10 }
11 printf("%d\n", count);
12 return 0;
13 }選項 A 正確(★ 本題標準答案)
每一輪外層迴圈中,內層 j=1、j=2 都會讓 count++(共 2 次),j=3 時就 break 跳出內層;外層總共跑 3 輪,因此 count 總共增加 3×2=6。
選項 B 錯誤
9 沒有正確反映 break 讓每輪內層只執行到 j=2(2 次)就停止的效果。
選項 C 錯誤
15(3×5)是假設內層完全不受 break 影響、每輪都跑滿 5 次才會得到的結果,但實際上 j=3 就已經 break。
選項 D 錯誤
3 只反映了外層迴圈的執行次數,忽略了內層迴圈每一輪也會讓 count 增加。
執行後輸出結果為何(含換行)?
1 #include <stdio.h>
2 int main(void) {
3 for (int i = 1; i <= 2; i++) {
4 for (int j = 1; j <= 2; j++) {
5 printf("%d*%d=%d ", i, j, i * j);
6 }
7 printf("\n");
8 }
9 return 0;
10 }選項 A 錯誤
行號 7 的 printf("\n") 寫在內層迴圈結束之後、外層迴圈內部,每跑完一整輪內層迴圈就會換一次行,因此不會全部擠在同一行。
選項 B 正確(★ 本題標準答案)
外層 i=1 時,內層 j=1,2 依序印出 "1*1=1 1*2=2 ",接著換行;外層 i=2 時,內層印出 "2*1=2 2*2=4 ",再換行,總共兩行。
選項 C 錯誤
此程式是先固定 i、讓 j 從 1 跑到 2,因此每一行是同一個 i 搭配不同的 j,不是同一個 j 搭配不同的 i(那樣才會得到這個選項描述的排列)。
選項 D 錯誤
每一次 printf 呼叫都會實際輸出,並不會被後面的呼叫覆蓋掉,因此所有計算結果都會被印出來,不會只剩最後一個。
若沒有行號 7 的 `if (count > 10) break;` 保護,這個迴圈原本會發生什麼問題?加上保護後,count 印出的值是多少?
1 #include <stdio.h>
2 int main(void) {
3 unsigned int i;
4 int count = 0;
5 for (i = 3; i >= 0; i--) {
6 count++;
7 if (count > 10) break;
8 }
9 printf("%d\n", count);
10 return 0;
11 }選項 A 錯誤
unsigned int 永遠不可能是負數,i 遞減到 0 之後再減 1 並不會讓迴圈自然結束,而是會環繞成極大的正整數,原本會造成無窮迴圈。
選項 B 錯誤
unsigned int 沒有負數這個概念,i 絕對不會「變成負數」,因此迴圈不會因此自然結束。
選項 C 正確(★ 本題標準答案)
i 遞減到 0 之後再減 1,因為型態是 unsigned int,會環繞成一個非常大的正整數,使得 i >= 0 恆為真,原本會是無窮迴圈;因為 count++ 與 break 判斷每輪都會執行,與 i 目前的值無關,第 11 次迭代時 count 變成 11 並觸發跳出,因此印出 11。
選項 D 錯誤
unsigned int 變數與 0 比較(`>= 0`)在語法上完全合法,不會造成編譯錯誤,只是這個判斷式的邏輯結果永遠是真。
關於在迴圈中使用 unsigned 型態當作計數器(例如迴圈變數)的敘述,下列何者正確?
選項 A 錯誤
unsigned 計數器並非絕對安全,它帶有特定且知名的風險,也就是遞減環繞的陷阱,不能說完全沒有風險。
選項 B 錯誤
遞增的 unsigned 計數器若持續加到型態能表示的最大值,同樣可能環繞回 0,因此「只要是遞增就不會有陷阱」的說法過於絕對,並不正確。
選項 C 錯誤
如第 15 題所示,unsigned 計數器的環繞問題會實際導致無窮迴圈或非法的陣列存取,並不是「不會造成任何實際的執行問題」。
選項 D 正確(★ 本題標準答案)
當 unsigned 計數器可能被減到 0 以下時(例如反向計數、倒數等情境),就會環繞成一個極大的正整數,這正是導致「原本應該結束卻變成無窮迴圈」最常見的成因。
承第 15 題的陷阱,若想要修正該迴圈,讓它能夠正確地從 3 數到 0(共 4 次),且不會有無窮迴圈的風險,下列哪一種修改方式最恰當?
選項 A 正確(★ 本題標準答案)
把 i 的型態從 unsigned int 改成一般的 int,可以讓 i 正確表示到 -1,迴圈就能在 i 遞減到 -1 時正常讓條件 `i >= 0` 判斷為假並結束,不會發生環繞。
選項 B 錯誤
把條件改成 `i > 0` 雖然可以避免無窮迴圈,但會在 i=0 時就提前結束(0 > 0 為假),導致只印出 3、2、1 共 3 個,漏掉了索引 0,並沒有完整達成「從 3 數到 0」的目標。
選項 C 錯誤
`i -= 1` 與 `i--` 在效果上完全相同,只是寫法不同,並不能解決 unsigned 環繞的根本問題。
選項 D 錯誤
i 仍然是 unsigned int,`-1` 在與 unsigned 比較時會被轉換成一個極大的正整數,`i >= -1` 幾乎恆為真,並不能正確地讓迴圈在 i 變成 -1(概念上)時結束,這個修法並不成立。
執行後輸出結果為何?
1 #include <stdio.h>
2 int main(void) {
3 int arr[10] = {0,1,2,3,4,5,6,7,8,9};
4 for (int i = 0; i < 10; i += 3) {
5 printf("%d ", arr[i]);
6 }
7 printf("\n");
8 return 0;
9 }選項 A 錯誤
此迴圈的步伐是 `i += 3`,並不是每個索引都走訪,不會印出全部 10 個元素。
選項 B 正確(★ 本題標準答案)
i 依序為 0、3、6、9(下一次會變成 12,因為 12<10 為假而停止),對應印出 arr[0]、arr[3]、arr[6]、arr[9],也就是 0、3、6、9。
選項 C 錯誤
12 已經超出 i<10 的條件,不會被拿來當索引印出,因此不會有第五個數字。
選項 D 錯誤
1、4、7 對應的是 i 從 1 開始、步伐 3 的走訪方式,與此程式從 i=0 開始的走訪不符。
執行後 count 印出的值是多少?(字串 "Hi!" 由 'H'、'i'、'!' 三個字元組成)
1 #include <stdio.h>
2 int main(void) {
3 char str[] = "Hi!";
4 int count = 0;
5 int i = 0;
6 while (str[i] != '\0') {
7 count++;
8 i++;
9 }
10 printf("%d\n", count);
11 return 0;
12 }選項 A 錯誤
4 誤把結尾的 '\0' 也當成一個要計數的字元,但迴圈條件在遇到 '\0' 時就會停止,不會把它算進 count。
選項 B 錯誤
2 少算了其中一個字元,"Hi!" 實際上有 H、i、! 三個字元。
選項 C 正確(★ 本題標準答案)
字串 "Hi!" 在記憶體中依序是 'H'、'i'、'!'、'\0',迴圈會在 str[0]、str[1]、str[2] 時累加 count(各遇到 H、i、!),直到 str[3]='\0' 才停止,因此 count 印出 3。
選項 D 錯誤
C 語言的字串常值(如 "Hi!")在編譯時就會自動在結尾加上 '\0' 終止字元,因此這個迴圈一定會正常結束,不會是無窮迴圈。
若呼叫 sumEven(arr, 5),其中 arr = {1, 2, 3, 4, 5},這個函式執行後的回傳值,以及這段程式碼的迴圈寫法,下列敘述何者正確?
1 int sumEven(int arr[], int size) {
2 int sum = 0;
3 for (int i = 0; i < size; i++) {
4 if (arr[i] % 2 == 0)
5 sum += arr[i];
6 }
7 return sum;
8 }選項 A 錯誤
行號 4 的 if 判斷式會過濾掉奇數元素,只有偶數才會被加進 sum,並不是把整個陣列全部加總。
選項 B 錯誤
`arr[i] % 2 == 0` 判斷的是「除以 2 餘數為 0」,也就是偶數,並不是奇數,這個選項把奇偶判斷弄反了。
選項 C 錯誤
`i < size` 讓 i 從 0 走訪到 size-1(此處是 0 到 4),剛好對應一個大小為 5 的陣列的合法索引範圍,不會有越界存取。
選項 D 正確(★ 本題標準答案)
迴圈正確走訪了索引 0 到 4(整個陣列),並用 `arr[i] % 2 == 0` 正確篩選出偶數 2 與 4,兩者相加為 6,這就是回傳值。