核心算法步驟
- 輸入年份
- 判斷閏年:
(y%4==0 && y%100!=0) || (y%400==0)
- 計算該年 1 月 1 日星期幾(蔡勒公式/基姆拉爾森公式)
- 按月迭代打印:對齊首行空格 → 逐日打印 → 換行邏輯
完整可運行代碼
#include
int is_leap(int y) {
return (y % 4 == 0 && y % 100 != 0) || (y % 400 == 0);
}
// 蔡勒公式:返回 0=周日 ... 6=周六
int weekday_1_1(int y) {
// 以 1900-01-01 (周一) 為基準
// 簡化版:1900 年 1 月 1 日是周一 (1)
int days = 0;
for (int i = 1900; i < y; i++)
days += is_leap(i) ? 366 : 365;
return (days + 1) % 7; // 0=Sun
}
void print_month(int year, int month, int *weekday) {
static const int mdays[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
int days = mdays[month - 1];
if (month == 2 && is_leap(year)) days = 29;
static const char *mname[12] = {
"January","February","March","April","May","June",
"July","August","September","October","November","December"
};
printf("\n %s %d\n", mname[month-1], year);
printf(" Sun Mon Tue Wed Thu Fri Sat\n");
// 打印首行前導空格
for (int i = 0; i < *weekday; i++) printf(" ");
for (int d = 1; d <= days; d++) {
printf("%4d", d);
if (++(*weekday) == 7) {
printf("\n");
*weekday = 0;
}
}
printf("\n");
}
int main() {
int year;
printf("輸入年份 (如 2024): ");
scanf("%d", &year);
int wd = weekday_1_1(year);
for (int m = 1; m <= 12; m++)
print_month(year, m, &wd);
return 0;
}
關鍵點解析
| 問題 | 解決方案 |
| 閏年判斷 | 標準格雷戈里曆規則,2 月 28/29 天動態調整 |
| 1月1日星期 | 蔡勒公式/累積天數法,注意基準日選擇 |
| 月曆對齊 | weekday 變量跨月傳遞,自動銜接上月結尾 |
| 輸出格式 | %4d 固定寬度,保證列對齊 |
| 十月末多一行 | 原代碼 if(i==10) 殘留邏輯導致,刪除即可 |
優化版:單行蔡勒公式
// 返回 0=周日 ... 6=周六,適用 1582 年後
int zeller(int y, int m, int d) {
if (m < 3) m += 12, y--;
return (d + 13*(m+1)/5 + y + y/4 - y/100 + y/400) % 7;
}
// 1月1日星期:zeller(year, 1, 1)
常見錯誤避坑
- 數組
day[12] 未隨閏年更新 2 月天數
week 變量未在月份間正確傳遞(需指針或全局)
- 打印循環中
week 遞增與換行判斷順序錯誤
- 輸入年份超出
int 範圍(不實際)
擴展功能建議
- 高亮今天(ANSI 色碼)
- 顯示農曆/節氣(查表/算法)
- 輸出 HTML/Markdown/圖片
- 命令行參數
./cal 2024 5 只顯示指定月
- 上一篇文章: C語言for循環機器周期分析:單片機延時計算實戰指南
- 下一篇文章: C語言二維陣列(N×N)轉置程式完整教學
Copyright ©
程式碼之家 All Rights Reserved