c语言万年历项目二次开发

原c语言代码如下:

点击查看代码(源码来自互联网,如有侵权请联系删除)
#define _CRT_SECURE_NO_WARNINGS 0
#include <stdio.h>
#include <windows.h>

//平年365天(52周 + 1天),闰年366天(52周 + 2天),平年2月28天,闰年2月29天。由于公元1月1日设为星期六,故3月1日为星期三。为使算法达到最简,故本算法以“星期”为计算单位,且选3月1日为基月。
//
//每400年整一闰,或每4年且不为百年的一闰,即凡能被400整除,或不能被100整除但能被4整除的年份为闰年。
//
//每4年(3个平年 + 1个闰年)共208周 + 5天
//
//每百年共100 * (208周 + 5天) - 1天 = 5217周 + 5天
//
//每400年共4 * (5217周 + 5天) + 1天(整400年闰) = 20871周 + 0天,即每400年一个轮回。


int total_days = 0;
int month_days = 0;
int week_days = 0;

int TotalDays(int year, int month)
{
    int y, mon;
    for (y = 1900; y < year; y++)
    {
        if ((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0))
        {
            total_days += 366;
        }
        else
        {
            total_days += 365;
        }
    }

    for (mon = 1; mon < month; mon++)
    {
        if (mon == 2)
        {
            if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
            {
                total_days += 29;
            }
            else
            {
                total_days += 28;
            }
        }
        else if (mon == 4 || mon == 6 || mon == 9 || mon == 11)
        {
            total_days += 30;
        }
        else
        {
            total_days += 31;
        }
    }

    return total_days;
}

int WeekDay(int year, int month)
{
    total_days += 1;
    week_days = total_days % 7;
    return week_days;
}

int MonthDays(int year, int month)
{
    if (month == 2)
    {
        if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
        {
            month_days = 29;
        }
        else
        {
            month_days = 28;
        }
    }
    else if (month == 4 || month == 6 || month == 9 || month == 11)
    {
        month_days = 30;
    }
    else
    {
        month_days = 31;
    }

    return month_days;
}

void print()
{
    int i, k;
    printf("日   一   二   三   四   五   六\n");
    for (i = 1; i <= week_days; i++)
    {
        printf("     ");
    }

    for (k = 1; k <= month_days; k++)
    {
        if (total_days % 7 == 6)
        {
            printf("%2d\n", k);
        }
        else
        {
            printf("%2d   ", k);
        }
        total_days++;
    }
    printf("\n\n");
}

int main()
{
    int year = 0, month = 0;
    printf("请输入查询时间:     年    月\n");
    scanf("%d", &year);
    scanf("%d", &month);
    printf("\n");

    TotalDays(year, month);
    WeekDay(year, month);
    MonthDays(year, month);
    print();

    return 0;
}

原程序代码运行截图:

image
为了检验程序是否正确,笔者比对了运行结果和手机的日历,验证了程序运行无误(当然,笔者做的测试次数较少,可能还存在问题)
image

原程序缺陷分析

这段程序存在一些潜在的问题和改进点:

  1. 全局变量问题: 程序中使用了全局变量 total_days,这样的设计会增加程序的复杂性,并且可能引发不可预测的错误。建议将其作为函数参数传递,以减少全局状态的影响。

  2. 函数设计不合理: 函数 TotalDaysWeekDayMonthDays 的功能重叠,而且 WeekDayMonthDays 函数中还修改了 total_days 全局变量。这样的设计使得程序难以理解和维护。建议将计算逻辑合理拆分,避免一个函数兼具多个功能。

  3. 未考虑用户输入错误: 程序没有对用户输入进行错误检查,如用户输入的年份或月份不合法,程序可能产生不正确的结果。建议增加输入验证机制,确保用户输入的数据是合理的。

  4. 日期计算问题: 闰年的判断条件可以简化为 (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)),这样更为清晰和简洁。

  5. 函数调用顺序混乱:main 函数中调用了 TotalDaysWeekDayMonthDays 函数,然后才调用 print 函数。这样的调用顺序可能导致 print 函数中的计算结果不准确。应该在所有计算完成后再调用 print 函数。

  6. 未充分利用函数: 函数的目的是封装独立的功能,但在此程序中,函数的封装性较差。建议重新设计函数,使其更加独立和具有清晰的功能。

  7. 魔法数值: 在程序中存在一些硬编码的魔法数值,如 6 和 7,这使得程序不易读懂和维护。建议使用有意义的常量或宏定义,提高代码的可读性。

  8. 缺乏注释: 程序中没有充分的注释,这可能使其他人难以理解代码的逻辑。建议添加注释,解释代码的关键部分和算法。

笔者进行的改进优化

点击查看代码
#include <stdio.h>

#define DAYS_IN_WEEK 7

// 函数声明
int IsLeapYear(int year);
int CalculateTotalDays(int year, int month);
int CalculateWeekDay(int year, int month);
int CalculateMonthDays(int year, int month);
void PrintCalendar(int weekDay, int monthDays);

int main() {
    int year = 0, month = 0;

    printf("请输入查询时间: 年 月\n");
    scanf("%d %d", &year, &month);
    printf("\n");

    int totalDays = CalculateTotalDays(year, month);
    int weekDay = CalculateWeekDay(year, month);
    int monthDays = CalculateMonthDays(year, month);

    PrintCalendar(weekDay, monthDays);

    return 0;
}

// 判断是否为闰年
int IsLeapYear(int year) {
    return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
}

// 计算总天数
int CalculateTotalDays(int year, int month) {
    int totalDays = 0;
    for (int y = 1900; y < year; y++) {
        totalDays += IsLeapYear(y) ? 366 : 365;
    }

    for (int mon = 1; mon < month; mon++) {
        totalDays += CalculateMonthDays(year, mon);
    }

    return totalDays;
}

// 计算星期几
int CalculateWeekDay(int year, int month) {
    return (CalculateTotalDays(year, month) + 1) % DAYS_IN_WEEK;
}

// 计算每月的天数
int CalculateMonthDays(int year, int month) {
    if (month == 2) {
        return IsLeapYear(year) ? 29 : 28;
    } else if (month == 4 || month == 6 || month == 9 || month == 11) {
        return 30;
    } else {
        return 31;
    }
}

// 打印日历
void PrintCalendar(int weekDay, int monthDays) {
    printf("日   一   二   三   四   五   六\n");

    for (int i = 0; i < weekDay; i++) {
        printf("     ");
    }

    for (int day = 1; day <= monthDays; day++) {
        if ((weekDay + day - 1) % DAYS_IN_WEEK == 6) {
            printf("%2d\n", day);
        } else {
            printf("%2d   ", day);
        }
    }

    printf("\n\n");
}

改进版本进行了以下优化:

  • 将全局变量替换为局部变量,减少了对全局状态的依赖。
  • 对函数进行了合理的拆分,提高了函数的独立性和可读性。
  • 使用宏定义替代硬编码的魔法数值,提高了代码的可维护性。
  • 添加了注释,解释了关键部分的代码逻辑。
  • 优化了用户输入的处理,通过 scanf 一次性获取年和月。
  • 在 main 函数中调整了函数的调用顺序,确保在调用 PrintCalendar 函数前所有的计算都已完成。

代码运行测试:
image

posted on 2024-03-02 20:22  江城qwe  阅读(115)  评论(0编辑  收藏  举报