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;
}
原程序代码运行截图:
为了检验程序是否正确,笔者比对了运行结果和手机的日历,验证了程序运行无误(当然,笔者做的测试次数较少,可能还存在问题)
原程序缺陷分析
这段程序存在一些潜在的问题和改进点:
-
全局变量问题: 程序中使用了全局变量
total_days
,这样的设计会增加程序的复杂性,并且可能引发不可预测的错误。建议将其作为函数参数传递,以减少全局状态的影响。 -
函数设计不合理: 函数
TotalDays
、WeekDay
和MonthDays
的功能重叠,而且WeekDay
和MonthDays
函数中还修改了total_days
全局变量。这样的设计使得程序难以理解和维护。建议将计算逻辑合理拆分,避免一个函数兼具多个功能。 -
未考虑用户输入错误: 程序没有对用户输入进行错误检查,如用户输入的年份或月份不合法,程序可能产生不正确的结果。建议增加输入验证机制,确保用户输入的数据是合理的。
-
日期计算问题: 闰年的判断条件可以简化为
(y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
,这样更为清晰和简洁。 -
函数调用顺序混乱: 在
main
函数中调用了TotalDays
、WeekDay
和MonthDays
函数,然后才调用print
函数。这样的调用顺序可能导致print
函数中的计算结果不准确。应该在所有计算完成后再调用print
函数。 -
未充分利用函数: 函数的目的是封装独立的功能,但在此程序中,函数的封装性较差。建议重新设计函数,使其更加独立和具有清晰的功能。
-
魔法数值: 在程序中存在一些硬编码的魔法数值,如 6 和 7,这使得程序不易读懂和维护。建议使用有意义的常量或宏定义,提高代码的可读性。
-
缺乏注释: 程序中没有充分的注释,这可能使其他人难以理解代码的逻辑。建议添加注释,解释代码的关键部分和算法。
笔者进行的改进优化
点击查看代码
#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 函数前所有的计算都已完成。
代码运行测试: