1 三種迴圈的本質與選用時機(for/while/do-while)
三種迴圈做的事情本質上都一樣——「重複執行一段程式碼」,差別只在什麼時候檢查要不要繼續。可以想成三種不同的用餐習慣:
| 迴圈 | 白話比喻 | 判斷時機 | 最少執行次數 |
|---|---|---|---|
for |
已經知道要繞操場跑幾圈,直接設定圈數 | 先判斷,條件包含在迴圈標頭裡 | 0 次(次數已知時通常不會是0,但條件一開始就不成立時可以是0) |
while |
檢查郵筒,有信才拿,沒信就不開箱 | 先判斷條件,條件為假就完全不進入 | 0 次 |
do-while |
自助餐先夾一口菜試吃,吃完才決定要不要繼續夾 | 先執行本體,執行完才判斷條件 | 1 次(不管條件一開始是真是假,本體一定會先跑一次) |
#include <stdio.h>
int main(void) {
int i;
// for:已知要跑5次
for (i = 1; i <= 5; i++) printf("%d ", i);
printf("\n");
// while:先判斷才做
i = 1;
while (i <= 5) { printf("%d ", i); i++; }
printf("\n");
// do-while:先做才判斷(本題條件一開始就成立,效果與while相同)
i = 1;
do { printf("%d ", i); i++; } while (i <= 5);
printf("\n");
return 0;
}
1 2 3 4 5
1 2 3 4 5
次數明確(跑N次、走訪陣列每個元素)→ 優先用 for;次數不確定、但知道停止條件(讀到檔案結尾、使用者輸入0才停)→ 用 while;必須先做一次才能判斷(先讀一次輸入才知道要不要繼續讀)→ 用 do-while。
2 for 迴圈語法拆解與執行順序
for(初始化; 條件; 遞增) 三段式寫法最容易讓人誤會執行順序。真正的執行順序是:
- 初始化——只執行一次,用來設定迴圈變數的起始值。
- 條件判斷——每一輪開始前都會檢查,為假就直接結束整個迴圈。
- 執行本體——條件為真才執行大括號裡的程式碼。
- 遞增/遞減——本體執行完後才做,接著回到步驟2重新判斷條件。
int i, total = 0;
for (i = 1; i < 8; i += 2)
total += i;
// i依序為 1、3、5、7(每次遞增2)
// total累加:0+1+3+5+7 = 16
// i變9時,9<8不成立,迴圈結束
| 輪次 | 條件判斷(i<8) | 執行本體 total+=i | 本體結束後 i+=2 |
|---|---|---|---|
| 1 | 1<8 → 真 | total=0+1=1 | i變3 |
| 2 | 3<8 → 真 | total=1+3=4 | i變5 |
| 3 | 5<8 → 真 | total=4+5=9 | i變7 |
| 4 | 7<8 → 真 | total=9+7=16 | i變9 |
| 5 | 9<8 → 假,結束 | (不執行) | — |
寫成 i < 8 跟 i <= 8 在遞增規律剛好卡在邊界時會產生不同的總輪數。逐輪手動列表追蹤(如上表)是最保險的做法,不要只憑直覺猜輪數。
3 while 與 do-while 的關鍵差異:先判斷 vs 先執行
兩者的差異只在「檢查條件」與「執行本體」誰先誰後,但這個順序在條件一開始就是假的情況下,會讓兩者的執行次數完全不同:
int n = 5, count = 0;
while (n < 3) { // 5<3為假,本體一次都不會執行
count++;
n--;
}
printf("while: count=%d\n", count); // 輸出 0
n = 5; count = 0;
do { // 不管條件,先執行一次
count++;
n--;
} while (n < 3); // 執行後n=4,4<3為假,結束
printf("do-while: count=%d\n", count); // 輸出 1
do-while: count=1
統測 112 年 Q46 出過一題:全域變數 int x = 100; 與 main() 內的區域變數 int x = 0; 同名。一旦函式內重新宣告了同名變數,這個區域變數會遮蔽(shadow)外層的全域變數,函式內所有用到 x 的地方都是指這個區域變數。這種情況下,不管怎麼修改全域 x 的初始值,對函式內的行為都完全沒有影響。
如果 do-while 本體的第一行就是 y = 某運算式;,那麼 y 宣告時的初始值在第一次比較條件之前早就已經被覆蓋,不管原本設定成什麼都不會影響任何一輪的判斷結果——跟第4章「flag 初始值被覆蓋」是同一種陷阱的迴圈版本。
4 break 與 continue 的差異與追蹤技巧
break 是「立刻、完全結束整個迴圈」;continue 只是「跳過這一輪剩下的程式碼,回到條件判斷繼續下一輪」。兩者效果差很多,追蹤程式時務必分清楚。
#include <stdio.h>
int main(void) {
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) continue; // 偶數:跳過本次,不印
if (i > 7) break; // 大於7:整個迴圈直接結束
printf("%d ", i);
}
printf("\n"); // 輸出: 1 3 5 7
return 0;
}
在 for 迴圈裡,continue 只會跳過本體剩下的程式碼,迴圈標頭的遞增運算式(如 i++)依然會照常執行。但在 while 迴圈裡,如果遞增變數是寫在本體最後一行(例如 i++;),continue 會連這行遞增也一起跳過!這會讓迴圈卡在同一個索引,重複比對同一個位置,統測 115 年 Q40 就是靠這個陷阱設計出「同一個位置被多算一次」的追蹤題。
5 巢狀迴圈(nested loop)執行次數推算與逐輪追蹤
巢狀迴圈就是「迴圈裡面還有迴圈」:外層迴圈每跑一輪,內層迴圈就會完整地從頭跑到尾一次。
#include <stdio.h>
int main(void) {
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++)
printf("%d*%d=%d ", i, j, i * j);
printf("\n");
}
return 0;
}
// 外層3次、內層3次,總共執行 3×3=9 次乘法運算
遇到巢狀迴圈題目,不要只憑直覺猜總執行次數,養成習慣列一張表:外層第幾輪、這一輪內層變數從哪裡跑到哪裡、這一輪對總結果貢獻了多少。尤其當內層迴圈的起始值或上限依賴外層變數時(例如 for(j=i; j<=5; j++)),每一輪外層迴圈內層實際跑的次數都不一樣,更需要逐輪列出來確認,不能套用固定次數。
只要累加變數(如 sum、total)是宣告在最外層迴圈之外,它就會持續累加每一輪外層與內層迴圈的貢獻,不會在外層迴圈的每一輪開始時被重設歸零。這是巢狀迴圈追蹤題最常見的失分點之一。
6 迴圈計數器溢位陷阱:unsigned 導致無窮迴圈(統測最愛的坑)
這是本章統測命中率最高的觀念!如果迴圈計數器被宣告為 unsigned(不含符號,只能表示0與正數),當它遞減到 0 以後再減1,並不會變成 -1,而是會整數溢位、環繞(wrap around)成該型態能表示的最大正數,導致「i >= 0」這種條件永遠為真,形成無窮迴圈。
unsigned short i;
for (i = 5; i >= 0; i--) { // 危險!i是unsigned,永遠 >= 0
printf("%d ", i);
} // i從0再減1不會變成-1,而是環繞成65535 → 無窮迴圈
| 型態 | 可表示範圍 | 0 再減 1 的結果 |
|---|---|---|
short(有號) | -32768 ~ 32767 | -1(正常遞減) |
unsigned short | 0 ~ 65535 | 環繞成 65535(絕不會變負數) |
unsigned char | 0 ~ 255 | 環繞成 255 |
把計數器宣告為 unsigned 完全不會造成編譯錯誤,程式可以正常編譯、正常執行前幾輪,只有在計數器真的遞減穿越 0 的那一刻才會出事——這正是它危險的原因:平常測試時如果剛好沒有觸發到邊界,這個 bug 很容易被忽略,直到上線後才爆發。
「unsigned 沒有負的家,減到底只會繞回來」——看到迴圈計數器宣告成 unsigned,且迴圈條件用 >= 0 搭配遞減,要立刻提高警覺檢查會不會無窮迴圈。
7 迴圈實務應用:陣列走訪步伐與字串走訪終止條件
迴圈最常見的實務用途就是走訪陣列與字串。這裡整理兩個統測愛考的實務技巧:
技巧一:用 for 迴圈的遞增步伐(step)跳著讀陣列
for(i=0; i<n; i+=2) 每次跳2格,可以只讀取陣列中偶數索引的元素,常用來在一組「正確資料+干擾資料」交錯排列的陣列中,只挑出真正需要的那些元素。
char S[9][4] = {"沖","收","脫","蓋","泡","沖","蓋","脫","送"};
// 索引:0=沖 1=收(干擾) 2=脫 3=蓋(干擾) 4=泡 5=沖(干擾) 6=蓋 7=脫(干擾) 8=送
for (int i = 0; i < 9; i += 2)
printf("%s", S[i]);
// 只印出索引0,2,4,6,8:沖脫泡蓋送(正確的燒燙傷急救步驟)
技巧二:用 while 迴圈走訪字串,直到遇見 '\0'
C 語言字串以 '\0'(空字元)作為結尾標記,走訪字串常寫成 while(str[i] != '\0'),代表「還沒走到結尾就繼續」。比對兩個長度不同的字串時,常用 || 讓迴圈跑到兩個字串都走到結尾才停止:
int i = 0;
char a[] = "abc#123456*789"; // 長度14
char b[] = "cba#987654*321"; // 長度14
while (a[i] != '\0' || b[i] != '\0') {
// 只要任一個字串在這個位置還沒結束,就繼續比對
i++;
}
結合第4節的陷阱:如果 i++ 是寫在 while 本體最後一行、而本體中間又有 continue,一旦觸發 continue,這一輪的 i++ 就不會執行,下一輪會重新比對同一個索引位置。這在字串比對類的追蹤題中是失分率最高的細節。
8 111~115 歷屆統測真題全選項深度剖析(共 8 題)
以下收錄統測專業科目(二)近年全部 8 題迴圈控制(for/while/do-while)真題。每題均提供高解析度原始考題掃描圖、互動選項按鈕與所有選項逐項深入解析:
int i, total=0;
for(i=1; i<8; i+=2)
total+=i;
🔍 四個選項逐項深度剖析
total+=i——要累加的是 i 本身當下的值,不是遞增的步伐量。9<8不成立,迴圈結束,total=16,選 (C)。i+=2(每次遞增2)誤看成 i++(每次只遞增1)的典型結果——若 i 真的逐一遞增為1,2,3,4,5,6,7,total 會變成1+2+3+4+5+6+7=28。這提醒我們必須看清楚遞增運算式寫的到底是 +=1 還是 +=2,不能只看到「i 在遞增」就直接假設是逐一加1。int y, r, a=30, b=42;
r=a%b;
while(r!=0)
{
a=b;
b=r;
r=a%b;
}
y=b;
🔍 四個選項逐項深度剖析
r=a%b=30%42,誤以為 a 比 b 小就代表「除不盡、餘數視為0」,讓迴圈條件 r!=0 一開始就被誤判為假,完全跳過迴圈本體,於是 y 直接等於 b 從未被改變過的初始值 42。實際上 30%42 的餘數就是 30 本身(因為30本來就小於42),r!=0 成立,迴圈一定會執行。y=b; 誤看成 y=a;,並且套用了 a 進入迴圈前的初始值30。但題目寫的明明白白是把 b 的值賦給 y,不是 a。r=30%12... 對,正確算法是a=30,b=12,r=30%12=6,此時 r=6,r!=0 仍然成立,還要再跑一輪(a=12,b=6,r=12%6=0)才會真正結束。r!=0不成立,迴圈結束。y=b=6,選 (D)。這正是計算最大公因數(GCD)的經典演算法。#include <stdio.h>
#include <math.h>
int x = 100;
int main(){
int x = 0;
double y = 0.0;
do{
y = 10*sin(x);
printf("x=%d, y=%lf\n", x, y);
} while(++x <= y);
printf("end of program\n");
return 0;
}
🔍 四個選項逐項深度剖析
main() 內用 int x = 0; 重新宣告了一個同名的區域變數,這個區域 x 會遮蔽(shadow)外層的全域 x,此後函式內所有的 x 都指向這個區域變數,修改全域 x 的初始值不會有任何作用。++x,每輪比較用的是「已經加1後」的新值,第1輪 x 先變1才比較 1<=0(y此時仍是初始的sin(0)*10=0)為假,只跑1次。改成後置遞增 x++ 後,比較用的是「還沒加1前」的舊值:第1輪 0<=0 真→x變1;第2輪 y=10sin(1)=8.415,1<=8.415 真→x變2;第3輪 y=10sin(2)≈9.09,2<=9.09 真→x變3;第4輪 y=10sin(3)≈1.41,3<=1.41 假,結束,共執行4次。y = 10*sin(x); 在第一次比較 ++x<=y 之前就已經先執行過一次,把 y 的值整個覆蓋掉了,因此 y 原本被設定的初始值(不論是0.0還是-1.0)從頭到尾都不會被拿來做真正的比較,是一個「死值」。main() 內實際使用的是 int x = 0; 這個區域宣告,跟全域 x 的初始值完全無關,改了也不會產生任何效果。int X=0, Y=0, Z;
printf("%c %c %c\n", 'A', 'B', 'F');
do{
while(Y<=1){
Z=((X||!Y)&&(Y||X));
printf("%d %d %d\n", X, Y, Z);
Y++;
}
Y=0;
X++;
}while(X<=1);
🔍 四個選項逐項深度剖析
B + AB̄ + AB = B + A(B̄+B) = B + A = A+B(也就是邏輯 OR)。代入 (A,B)=(0,1):A+B=1,但程式實際追蹤出的真值表在 X=0,Y=1 時 Z=0(因為 X||!Y=0||0=0,導致整個 AND 為0),兩者不符,此選項與第2組真值矛盾。A + ĀB̄ + AB = 0 + (1×1) + 0 = 1,但程式追蹤出 X=0,Y=0 時 Z=((0||!0)&&(0||0))=((0||1)&&(0))=(1&&0)=0,兩者不符,此選項與第1組真值矛盾。ĀB + AB = B(Ā+A) = B。代入 (A,B)=(1,0):B=0,但程式追蹤出 X=1,Y=0 時 Z=((1||!0)&&(0||1))=((1||1)&&(1))=(1&&1)=1,兩者不符,此選項與第3組真值矛盾。(A+B̄)(A+B) = A·A + A·B + A·B̄ + B̄·B = A + A(B+B̄) + 0 = A + A = A,與追蹤結果完全相符,選 (D)。char S[12][4]={"沖","收","脫","蓋","泡","沖","蓋","脫","送"};
void main(void){
printf("%s",S[i]);
}
🔍 四個選項逐項深度剖析
for(i=0;i<5;i++) 會依序印出 S[0]~S[4],也就是「沖、收、脫、蓋、泡」——把索引1的干擾資料「收」也印了出來,而且完全沒印到最後的「送」,順序既不完整也混入了假資料。for(i=1;i<6;i++) 會依序印出 S[1]~S[5],也就是「收、脫、蓋、泡、沖」——起始索引就選錯了(從干擾資料「收」開始),印出的順序完全不對應正確的急救步驟。for(i=0;i<9;i+=2),選 (C)。for(i=1;i<10;i+=2) 會印出 S[1],S[3],S[5],S[7],S[9],也就是「收、蓋、沖、脫」加上索引9(陣列只初始化了9個字串,索引9的內容是空字串),起始索引偏移了1,反而挑中了全部的干擾假資料,完全偏離正確的急救步驟。unsigned short i = 0, c = 0;
char stringA[]="abc#123456*789";
char stringB[]="cba#987654*321";
while(stringA[i]!='\0'||stringB[i]!='\0'){
if(stringA[i] == stringB[i])
c++;
if(c == 3)
{ continue; }
i++;
}
printf("c=%d", c);
🔍 四個選項逐項深度剖析
if(c==3){continue;} 誤讀成 if(c==3){break;},以為第三次比對相符(i=8時 '5'='5')就會讓整個迴圈立刻結束,計數停在3。但程式碼寫的是 continue,只會跳過這一輪剩下的程式碼(也就是跳過 i++;),迴圈並不會結束,後面還有更多字元要繼續比對。continue 讓 i=8 這個位置被多比對了一次(c從3變成4),但誤以為迴圈在這之後就結束了,忽略了後面 i=10 時兩個字串都是 '*',還會再相符一次,讓 c 再加1。continue,跳過 i++ 直接回到 while 判斷,i 仍為8,再次比對 stringA[8] 與 stringB[8] 仍然相等,c 再加1變成4(此時 c==3 已不成立,不再觸發 continue),i++ 變9;i=9('6'≠'4')不相符;i=10('*'='*')c=5;i=11~13皆不相符;i=14兩字串都走到 '\0',迴圈結束。最終 c=5,選 (C)。continue 被重複比對了兩次以上(而不是恰好一次),或是把後面某個原本不相符的位置(例如 i=9 的 '6' 與 '4')誤判成相符,多算了一次,導致總數比正確答案多了1。unsigned short sum = 0, i;
int stars[10]={3,5,4,2,1,5,4,0,4,3};
float average = 0.0;
for(i = 9; i >= 0; i--)
sum+=stars[i];
printf("總評價為 %d 顆星\n", sum);
printf("平均評價為 %.1f 顆星\n", (float)sum/10);
🔍 四個選項逐項深度剖析
i<=10 會讓迴圈存取 stars[10],但陣列 stars[10] 只宣告了10個元素、有效索引是0~9,stars[10]是超出陣列範圍的存取;而且從 i=1 開始又漏算了 stars[0],兩個新錯誤加在一起,並不能正確修好這支程式。unsigned short,遞減到0以下時一樣會溢位環繞成一個超大正數,i>=0 依然恆為真,無窮迴圈的問題完全沒有改善;而且起始值 i=10 一開始就會存取超出範圍的 stars[10],反而讓問題更早發作。average 宣告的型態從 float 改成 double,只會影響變數 average 本身的精度,跟迴圈條件、i 的正負號完全無關;即使改了,迴圈依然會因為 unsigned 溢位而無窮迴圈,程式還是跑不到後面的 printf,這個選項改的是不相關的地方。unsigned short,其值永遠不會小於0,故 i>=0 恆為真,形成無窮迴圈(i從0再 i-- 會溢位環繞成65535,之後還會持續以超出陣列範圍的巨大索引存取 stars[i]),導致程式跑不到後面的 printf。將 unsigned 刪除,讓 i 變成有號 short,遞減到 -1 時 i>=0 為假,迴圈才能正常結束,選 (D)。int i, j, sum;
i = 0; sum = 0;
while(i < 5){
sum = sum + i;
for(j = i; j <= 5; j++)
sum = sum + j;
i = i + 2;
}
🔍 四個選項逐項深度剖析
j<=5 誤看成 j<5,導致每一輪內層迴圈都少加了最後一個 j=5 的值:i=0輪內層只加0+1+2+3+4=10;i=2輪內層只加2+3+4=9;i=4輪內層只加4=4;總和=(0+10)+(2+9)+(4+4)=10+11+8=29。三輪剛好都各少加了一次「j=5」,合計少加15(44-29=15),正好等於三輪都漏掉的5×3。sum = sum + i;,誤以為只有內層 for 迴圈在累加 sum:三輪內層 for 迴圈分別加總15(i=0:0~5)、14(i=2:2~5)、9(i=4:4~5),15+14+9=38。忽略的 sum+=i 三輪合計恰好是0+2+4=6(44-38=6),正好對得上。sum+=0→sum=0;內層 j=0~5 累加0+1+2+3+4+5=15→sum=15;i變2。i=2(2<5成立):sum+=2→sum=17;內層 j=2~5 累加2+3+4+5=14→sum=31;i變4。i=4(4<5成立):sum+=4→sum=35;內層 j=4~5 累加4+5=9→sum=44;i變6,6<5為假,跳出迴圈。最終 sum=44,選 (C)。9 高職段考與模擬精選實戰題(5 題全選項解析)
透過以下 5 題精選模擬試題,全面檢驗你對三種迴圈差異、break/continue、巢狀迴圈與 unsigned 溢位陷阱的掌握度:
int i, total = 100;
for (i = 10; i > 0; i -= 3)
total -= i;
printf("%d", total);
🔍 四個選項逐項深度剖析
-2>0 不成立,迴圈結束)。total 逐輪扣減:100-10=90,90-7=83,83-4=79,79-1=78。最終 total=78,選 (A)。i>0 在 i=1 這一輪之前就已經不成立,只扣掉了10+7+4=21,100-21=79,忽略了 i=1 時 1>0 依然成立,這一輪仍然會執行。total -= i(減法賦值)誤看成 total += i(加法賦值),符號看反了,算成100+22=122。這是統測最愛考的「複合賦值運算子方向」陷阱——-= 與 += 只差一個符號,代表的運算方向完全相反。int n = 5, count = 0;
while (n < 3) {
count++;
n--;
}
printf("while: count=%d\n", count);
n = 5; count = 0;
do {
count++;
n--;
} while (n < 3);
printf("do-while: count=%d\n", count);
🔍 四個選項逐項深度剖析
while 在進入迴圈前就先檢查 n<3(5<3為假),本體完全不會執行,count 維持0。do-while 不管條件,先執行一次本體(count變1,n變4),才檢查 4<3(假),迴圈結束,count=1。所以 while:0,do-while:1,選 (B)。int i, sum = 0;
for (i = 1; i <= 6; i++) {
if (i == 3) continue;
if (i == 5) break;
sum += i;
}
printf("%d", sum);
🔍 四個選項逐項深度剖析
continue 在 for 迴圈裡會連迴圈標頭的遞增(i++)也一起跳過,導致 i 卡在3不會變成4,進而少加了 i=4 這一輪。但 for 迴圈的 continue 只跳過本體「剩下的程式碼」,並不會跳過迴圈標頭裡的遞增運算式,i 依然會正常變成4。continue,跳過 sum+=3,但迴圈標頭的 i++ 依然照常執行,i變4。i=4:sum+=4=7。i=5:觸發 break,在 sum+=5 之前就整個跳出迴圈。最終 sum=7,選 (B)。break 只會跳出「這一層 if」而不是整個迴圈,以為 i=5 那一輪雖然觸發 break,sum+=i 仍然有機會先執行。但 break 的本意就是立刻、完全終止整個迴圈,連同一輪剩下的程式碼(包含 sum+=i)都不會執行。continue(i==3那次)完全沒有任何效果,讓 i=3 那一輪也正常執行了 sum+=3,只有 break(i==5那次)在真正發生前那一輪仍正常累加:1+2+3+4+5=15。這反映對「continue 會確實跳過本次累加,但迴圈仍會繼續進行下一輪」這件事理解不完整。int i, j, sum = 0;
for (i = 1; i <= 3; i++) {
for (j = 1; j <= i; j++) {
sum += j;
}
}
printf("%d", sum);
🔍 四個選項逐項深度剖析
j<i(嚴格小於),而不是程式碼實際寫的 j<=i,導致每一輪內層迴圈都少跑最後一次(j=i那次):i=1時內層完全不執行(貢獻0);i=2時只跑j=1(貢獻1);i=3時只跑j=1,2(貢獻3);總和0+1+3=4。j<=i 會隨外層 i 逐輪增加,而 sum 會持續累加每一輪的貢獻。j<=3,而不是隨外層 i 變動的 j<=i,導致誤判每一輪外層迴圈的內層都固定跑3次、加總都是1+2+3=6,三輪外層迴圈總共6+6+6=18,忽略了內層迴圈實際執行的範圍其實會隨外層 i 的值逐輪增加,並不是固定的。unsigned char i;
for (i = 5; i >= 0; i--) {
printf("%d ", i);
}
printf("done");
🔍 四個選項逐項深度剖析
unsigned char,數值範圍只能是0~255,永遠不可能是負數。當 i=0 時執行 i--,並不會變成-1,而是「環繞(wrap around)」變成255(unsigned char 能表示的最大值),所以 i>=0 這個條件永遠是真,迴圈並不會在印出0之後正常結束,“done”永遠不會被印出來。unsigned char是255),導致 i>=0 恆為真,形成無窮迴圈,會不斷印出255、254、253……一路循環下去,“done”永遠不會被印出來,選 (B)。unsigned 宣告用在迴圈計數器完全合法,可以正常通過編譯,這不是語法錯誤,而是一個能順利通過編譯、卻在執行期造成無窮迴圈的邏輯陷阱——往往比編譯期就能抓到的錯誤更難察覺,也更危險。10 考前衝刺 10 秒速記口訣 & 核心知識檢核清單
次數已知用 for;先判斷才做用 while;至少要做一次才判斷用 do-while。
初始化(僅一次)→ 條件判斷 → 執行本體 → 遞增/遞減 → 回到條件判斷。
break 立刻完全結束整個迴圈;continue 只跳過本次剩下的程式碼,回到條件判斷。
若遞增變數寫在本體最後一行,continue 會連遞增也一起跳過,導致同一位置被重複處理。
「unsigned 沒有負的家,減到底只會繞回來」——看到 unsigned 計數器搭配遞減與 >=0,立刻提高警覺。
外層每跑一輪,內層就完整跑一次;累加變數宣告在外層迴圈外就不會被中途重設。
函式內重新宣告同名變數會遮蔽外層同名變數,修改外層的那個對函式內完全無效。