C语言万年历编写如何实现?

99ANYc3cd6
预计阅读时长 20 分钟
位置: 首页 C语言 正文

下面我将为你提供一个完整、详细、可运行的C语言万年历程序,并逐步解析其核心原理和代码结构。

怎么用c语言编写万年历
(图片来源网络,侵删)

核心算法:基姆拉尔森计算公式

万年历的核心问题是如何根据给定的年、月、日,计算出这一天是星期几,目前最常用和最高效的方法是 基姆拉尔森计算公式 (Zeller's Congruence)

这个公式可以计算从公元1年1月1日以来的任意一天是星期几。

公式: W = (d + 2m + 3(m+1)/5 + y + y/4 - y/100 + y/400) % 7

  • W 是计算出的星期结果。0 代表星期日,1 代表星期一,...,6 代表星期六。
  • d 是日。
  • m 是月。注意:如果月份是1月或2月,则需要将其视为上一年的13月或14月,2025年1月,计算时 m 应为 13,y 应为 2025。
  • y 是年。同样,如果月份是1月或2月,y 需要减1

C语言完整代码

下面是完整的C语言代码,包含了注释,方便你理解每一部分的功能。

怎么用c语言编写万年历
(图片来源网络,侵删)
#include <stdio.h>
#include <stdbool.h>
// 函数声明
bool isLeapYear(int year);
int getDaysInMonth(int year, int month);
int getWeekday(int year, int month, int day);
void printCalendar(int year, int month);
int main() {
    int year, month;
    printf("欢迎使用万年历!\n");
    printf("请输入年份 ( 2025): ");
    scanf("%d", &year);
    printf("请输入月份 (1-12): ");
    scanf("%d", &month);
    // 验证输入的月份是否有效
    if (month < 1 || month > 12) {
        printf("错误:月份必须在1到12之间,\n");
        return 1; // 非正常退出
    }
    printf("\n");
    printf("----------------------------\n");
    printf("      %d年 %d月\n", year, month);
    printf("----------------------------\n");
    // 打印星期标题
    printf(" 日  一  二  三  四  五  六\n");
    // 调用函数打印日历
    printCalendar(year, month);
    return 0;
}
/**
 * @brief 判断是否为闰年
 * @param year 年份
 * @return 如果是闰年返回 true,否则返回 false
 */
bool isLeapYear(int year) {
    if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
        return true;
    }
    return false;
}
/**
 * @brief 获取某年某月的天数
 * @param year 年份
 * @param month 月份
 * @return 该月的天数
 */
int getDaysInMonth(int year, int month) {
    // 使用数组来存储每个月的天数,索引0不用,从1开始
    int daysInMonth[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    // 如果是闰年的2月,天数加1
    if (month == 2 && isLeapYear(year)) {
        return 29;
    }
    return daysInMonth[month];
}
/**
 * @brief 使用基姆拉尔森公式计算星期几
 * @param year 年份
 * @param month 月份
 * @param day 日
 * @return 返回 0 (星期日), 1 (星期一), ..., 6 (星期六)
 */
int getWeekday(int year, int month, int day) {
    int y, m, d;
    // 如果月份是1月或2月,需要转换为上一年的13月或14月
    if (month < 3) {
        m = month + 12;
        y = year - 1;
    } else {
        m = month;
        y = year;
    }
    d = day;
    // 应用基姆拉尔森公式
    int weekday = (d + 2*m + 3*(m+1)/5 + y + y/4 - y/100 + y/400) % 7;
    // 公式返回的0代表星期六,我们需要调整一下,让0代表星期日
    // 公式结果: 0=Sat, 1=Sun, 2=Mon, 3=Tue, 4=Wed, 5=Thu, 6=Fri
    // 我们想要: 0=Sun, 1=Mon, ..., 6=Sat
    // 如果结果是0(星期六),我们让它变成6,其他情况减1。
    if (weekday == 0) {
        return 6;
    } else {
        return weekday - 1;
    }
}
/**
 * @brief 打印指定年月的日历
 * @param year 年份
 * @param month 月份
 */
void printCalendar(int year, int month) {
    int daysInMonth = getDaysInMonth(year, month);
    int weekdayOfFirstDay = getWeekday(year, month, 1); // 获取该月1日是星期几
    int dayCounter = 1;
    // 打印前面的空格
    for (int i = 0; i < weekdayOfFirstDay; i++) {
        printf("    "); // 4个空格,对齐日期
    }
    // 打印日期
    while (dayCounter <= daysInMonth) {
        printf("%4d", dayCounter); // 使用%4d保证每个日期占4个字符宽度,对齐
        dayCounter++;
        // 如果当前是星期六(即6),或者已经打印完该月最后一天,则换行
        if ((dayCounter - 1 + weekdayOfFirstDay) % 7 == 0 || dayCounter > daysInMonth) {
            printf("\n");
        }
    }
}

代码分步解析

主函数 main()

  • 输入:程序首先提示用户输入年份和月份。
  • 验证:检查月份是否在1-12的有效范围内,如果无效则报错退出。
  • 调用:调用 printCalendar(year, month) 函数来执行核心的打印任务。
  • 输出:打印一个简单的标题,然后调用函数打印日历主体。

辅助函数

这些函数负责完成具体的计算任务,使主函数更简洁。

  • bool isLeapYear(int year)

    • 功能:判断给定的年份是否是闰年。
    • 逻辑:遵循闰年规则:能被4整除但不能被100整除,或者能被400整除。
    • 返回值true (是闰年) 或 false (不是闰年)。
  • int getDaysInMonth(int year, int month)

    • 功能:获取某年某月的天数。
    • 逻辑
      1. 定义一个数组 daysInMonth,存储了“非闰年”中每个月的天数,使用数组可以方便地查询,效率高。
      2. 如果月份是2月,isLeapYear(year) 返回 true,则返回29天,否则返回数组中的值。
    • 返回值:该月的天数(28, 29, 30, 或 31)。
  • int getWeekday(int year, int month, int day)

    怎么用c语言编写万年历
    (图片来源网络,侵删)
    • 功能:万年历的核心,计算给定日期是星期几。
    • 逻辑
      1. 处理1月和2月的情况:将它们视为上一年的13月和14月。
      2. 代入基姆拉尔森公式进行计算。
      3. 对公式结果进行调整,使其符合 0=星期日 的习惯。
    • 返回值:0到6,分别代表星期日到星期六。

核心打印函数 printCalendar(int year, int month)

这个函数负责将日历格式化输出到屏幕上。

  • 获取信息

    • 调用 getDaysInMonth() 获取该月总共有多少天。
    • 调用 getWeekday() 获取该月第一天是星期几,这个信息至关重要,它决定了日历第一行前面需要空出多少个位置。
  • 打印空格

    • 使用一个 for 循环,循环次数等于第一天是星期几(weekdayOfFirstDay)。
    • 每次循环打印4个空格,用于对齐日期,如果1号是星期三(weekdayOfFirstDay = 3),那么就在前面打印3组空格。
  • 打印日期

    • 使用一个 while 循环,从 dayCounter = 1 开始,循环到该月总天数。
    • 使用 printf("%4d", dayCounter) 来打印每一天。%4d 确保每个数字都占据4个字符宽度,这样无论是个位数还是两位数,都能完美对齐。
    • 换行逻辑:这是打印的关键,每当打印完一个星期六(即 (dayCounter - 1 + weekdayOfFirstDay) % 7 == 0 这个条件成立时),或者打印完该月最后一天时,就执行一次换行 (\n),这个公式巧妙地结合了当前日期和起始星期,来判断是否应该换行。

如何编译和运行

  1. 保存代码:将上面的代码复制并粘贴到一个文本文件中,命名为 calendar.c
  2. 打开终端/命令行
    • 在Windows上,你可以使用 cmdPowerShell
    • 在macOS或Linux上,打开 Terminal
  3. 编译代码:使用GCC编译器进行编译。
    gcc calendar.c -o calendar
    • gcc 是编译器命令。
    • calendar.c 是你的源文件名。
    • -o calendar 指定输出的可执行文件名为 calendar
  4. 运行程序
    ./calendar
  5. 交互:程序会提示你输入年份和月份,输入后按回车,即可看到该月的日历。

示例运行

欢迎使用万年历!
请输入年份 ( 2025): 2025
请输入月份 (1-12): 10
----------------------------
      2025年 10月
----------------------------
 日  一  二  三  四  五  六
       1  2  3  4  5
 6  7  8  9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31

这个程序结构清晰,逻辑完整,是学习C语言和算法的一个很好的范例,你可以基于这个代码进行扩展,比如增加“打印全年日历”的功能,或者美化输出格式等。

-- 展开阅读全文 --
头像
织梦源码自适应手机效果如何实现?
« 上一篇 今天
计算机二级C语言模拟题在哪找?
下一篇 » 今天

相关文章

取消
微信二维码
支付宝二维码

目录[+]