同前題,但要求使用 while 循環輸入 3 位學生 3 門課成績並計算總分平均分。核心考點:while 循環計數器模式、循環變體等價性、計數器初始化與更新位置。
#include <stdio.h>
int main() {
int n = 0;
float n1, n2, n3, sum, avg;
while (n++ < 3) { // 後置++:先判斷再遞增
printf("請輸入第 %d 個同學三門分數: ", n);
scanf("%f %f %f", &n1, &n2, &n3);
sum = n1 + n2 + n3;
avg = sum / 3;
printf("總分 %.2f, 平均分 %.2f\n", sum, avg);
}
return 0;
}
int n = 0;
// 版本 A: while (n++ < 3) -- 原代碼
// 迭代 1: n=0 條件真(0<3) → n變1 → 體內 n=1
// 迭代 2: n=1 條件真(1<3) → n變2 → 體內 n=2
// 迭代 3: n=2 條件真(2<3) → n變3 → 體內 n=3
// 迭代 4: n=3 條件假(3<3) → 結束
// 體內 n 取值: 1, 2, 3 ✓ 正確
// 版本 B: while (++n < 3)
// 迭代 1: n=0 → 先增為1 → 條件真(1<3) → 體內 n=1
// 迭代 2: n=1 → 先增為2 → 條件真(2<3) → 體內 n=2
// 迭代 3: n=2 → 先增為3 → 條件假(3<3) → 結束
// 體內 n 取值: 1, 2 ✗ 少一次!
// 版本 C: while (n < 3) { n++; ... } -- 最清晰推薦
// 迭代 1: n=0 條件真 → 體內先 n=1 → 用 n=1
// 迭代 2: n=1 條件真 → 體內先 n=2 → 用 n=2
// 迭代 3: n=2 條件真 → 體內先 n=3 → 用 n=3
// 體內 n 取值: 1, 2, 3 ✓ 正確且語義明確
| 循環類型 | 代碼模式 | 適用場景 | 特點 |
|---|---|---|---|
| for | for(int i=1;i<=3;i++) | 已知次數計數 | 初始化/條件/更新集中,最標準 |
| while | while(n<3){n++;...} | 條件驅動、次數可變 | 條件獨立,體內手動更新計數器 |
| do-while | do{...}while(n++<3); | 至少執行一次 | 先執行後判斷,菜單交互常用 |
int n = 0;
do {
n++;
printf("學生 %d: ", n);
scanf("%f %f %f", &n1, &n2, &n3);
sum = n1 + n2 + n3;
avg = sum / 3;
printf("總分 %.2f 平均 %.2f\n", sum, avg);
} while (n < 3);
原代碼每次循環覆蓋 n1,n2,n3,sum,avg,**無法事後統計全班總平均、最高分等**。改進:用數組保存。
float sums[3], avgs[3];
int n = 0;
while (n < 3) {
printf("學生 %d: ", n+1);
scanf("%f %f %f", &n1, &n2, &n3);
sums[n] = n1 + n2 + n3;
avgs[n] = sums[n] / 3;
printf("總分 %.2f 平均 %.2f\n", sums[n], avgs[n]);
n++;
}
// 循環後可進一步分析
float class_avg = (avgs[0] + avgs[1] + avgs[2]) / 3;
printf("全班平均: %.2f\n", class_avg);
while 循環成績統計揭示了計數器更新位置語義差異與數據保存必要性。關鍵收穫:
while(n++ 與 while(++n 體內計數器值不同,易出錯; while (n < N) { n++; ... } 或 for 循環;do-while 保證至少一次執行,適合菜單/輸入驗證;