定義日期結構體 (年、月、日),輸入日期,計算該日是當年的第幾天。核心考點:結構體定義與使用、閏年判斷、累加月天數。原代碼閏年判斷函數有嚴重 Bug,需重點修正。
struct date { int year, month, day; };
int checkyear(int n) {
if ((n%4==0 && n%100!=0) || n%400==0) // 閏年條件正確
return 0; // ❌ Bug: 閏年返回 0
else
return 0; // ❌ Bug: 平年也返回 0
}
// 導致 main 中 if(flag) 永假,閏年 2 月天數永不加 1
return 0;。
#include <stdio.h>
#include <stdbool.h> // C99 bool 類型
struct Date {
int year;
int month;
int day;
};
// 正確閏年判斷:閏年返回 true (1)
bool is_leap_year(int year) {
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
// 累積每月天數表(平年)
const int DAYS_IN_MONTH[13] = {
0, // 0 佔位,月份 1-12 對應下標
31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31
};
int day_of_year(struct Date d) {
int day_count = d.day;
// 累加前 (month-1) 月天數
for (int m = 1; m < d.month; m++) {
day_count += DAYS_IN_MONTH[m];
}
// 閏年且月份 > 2,補 1 天
if (is_leap_year(d.year) && d.month > 2) {
day_count += 1;
}
return day_count;
}
int main() {
struct Date birthday;
printf("輸入日期 (年 月 日): ");
if (scanf("%d %d %d", &birthday.year, &birthday.month, &birthday.day) != 3) {
printf("輸入格式錯誤\n");
return 1;
}
// 簡單合法性檢查
if (birthday.month < 1 || birthday.month > 12 ||
birthday.day < 1 || birthday.day > 31) {
printf("月份或日期超出範圍\n");
return 1;
}
int doy = day_of_year(birthday);
printf("%d 年第 %d 天\n", birthday.year, doy);
return 0;
}
is_leap_year 明確語義;bool (C99) 或 int (1/0);return 表達式,無分支覆蓋 Bug 風險。m < d.month原代碼 i < birthday.month 會多加當月天數,再加 birthday.day 導致重複。正確邏輯:只加前 (month-1) 月,最後加 day。
month > 2閏日是 2 月 29 日,只有 3 月及以後才受影響。1-2 月無需補償。
檢查 scanf 返回值、月份/日期基本範圍,防禦性編程。
// 累積天數表:平年每月 1 日是第幾天 (1月1日=1)
const int CUMULATIVE_DAYS[13] = {
0, // 0月
0, // 1月1日 = 第1天 → 前0天
31, // 2月1日 = 第32天 → 前31天
59, 90, 120, 151, 181, 212, 243, 273, 304, 334 // 3-12月
};
int day_of_year_fast(struct Date d) {
int doy = CUMULATIVE_DAYS[d.month] + d.day;
if (is_leap_year(d.year) && d.month > 2) doy++;
return doy;
}
查表法將 O(month) 循環降為 O(1),嵌入式/高性能場景首選。
| 日期 | 預期年間天數 | 說明 |
|---|---|---|
| 2023-01-01 | 1 | 年初 |
| 2023-02-28 | 59 | 平年2月底 |
| 2024-02-29 | 60 | 閏年2月29日 |
| 2024-03-01 | 61 | 閏年3月1日(閏日後+1) |
| 2023-12-31 | 365 | 平年年尾 |
| 2024-12-31 | 366 | 閏年年尾 |
日期計算是結構體、閏年邏輯、邊界條件的綜合練習。原代碼 Bug 揭示了返回值語義不清導致邏輯失效的典型教訓。關鍵收穫:
(y%4==0&&y%100!=0) || y%400==0;