題目:輸入同年的兩個生日(月/日),輸出兩日期相差天數。原代碼邏輯正確,但 switch 缺少 break 導致 Case 貫穿,造成累加天數錯誤。以下詳細解析並給出修正版。
switch(i) {
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
s += 31;
case 4: case 6: case 9: case 11: // ❌ 無 break,31天月份會繼續執行這裡再加 30
s += 30;
case 2: // ❌ 繼續執行閏年判斷
if (leap) s += 29; else s += 28;
}
結果:1 月會被加上 31 + 30 + 28/29 = 89/90 天,完全錯誤。
#include
#include
// 計算該年 1 月 1 日至指定月日 的天數(1-based)
int dayOfYear(int year, int month, int day) {
static const int monthDays[12] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
int sum = 0;
for (int m = 1; m < month; ++m) {
if (m == 2) {
// 閏年判斷:能被400整除,或能被4整除但不能被100整除
int leap = (year % 400 == 0) || (year % 4 == 0 && year % 100 != 0);
sum += leap ? 29 : 28;
} else {
sum += monthDays[m - 1];
}
}
return sum + day;
}
int main() {
int year, m1, d1, m2, d2;
if (scanf("%d %d %d", &year, &m1, &d1) != 3) return 1;
if (scanf("%d %d", &m2, &d2) != 2) return 1;
int n1 = dayOfYear(year, m1, d1);
int n2 = dayOfYear(year, m2, d2);
int diff = abs(n1 - n2);
printf("%d\n", diff);
return 0;
}
| 原代碼問題 | 修正做法 |
|---|---|
switch 缺 break 導致貫穿 | 改用陣列 monthDays + 迴圈,完全避開 switch |
| 閏年判斷條件寫在 case 內,易漏 break | 獨立函式 isLeap(year) 判斷,邏輯清晰 |
| 輸入格式假設固定,無錯誤處理 | 檢查 scanf 返回值,增強健壯性 |
| 變數命名單一字母,可讀性差 | 語義化命名:dayOfYear, monthDays, leap |
輸入:
1997 2 27
3 10
輸出:
11 ← 正確(3/10 是第 69 天,2/27 是第 58 天,差 11 天)
輸入:
2000 1 1
12 31
輸出:
365 ← 閏年 366 天,首尾相差 365 天
改用標準庫 <time.h> 的 struct tm + mktime 轉換為 time_t 相減,自動處理閏年、跨年、時區:
time_t toTimeT(int y, int m, int d) {
struct tm t = {0};
t.tm_year = y - 1900;
t.tm_mon = m - 1;
t.tm_mday = d;
return mktime(&t);
}
double diffDays = difftime(toTimeT(y2,m2,d2), toTimeT(y1,m1,d1)) / 86400.0;
核心教訓:C 語言 switch 須加 break,否則會貫穿執行後續 case;改用資料驅動(陣列/表格)往往比分支語句更簡潔、不易出錯。