软件开发与创新——万年历功能新增与代码优化

news/2025/2/26 22:54:04/文章来源:https://www.cnblogs.com/liu2352837/p/18739982

一、项目名称与来源
上海海洋大学C语言期末大作业
二、原项目运行
运行环境:
系统:Windows11 24H2
cpu:i7-10750H
编译器:Dev c++ 5.11
运行结果:

点击查看代码
#include <stdio.h>
#include <stdlib.h>// 定义每个月的天数,第一行为平年,第二行为闰年
int dateofmonth[2][12] = {{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};// 英文月份名称数组
char *month1[] = {"January", "February", "March", "April", "May", "June","July", "August", "September", "October", "November", "December"
};// 中文月份名称数组
char *month2[] = {"一月", "二月", "三月", "四月", "五月", "六月","七月", "八月", "九月", "十月", "十一月", "十二月"
};// 中文星期名称数组
char *week[7] = {"日", "一", "二", "三", "四", "五", "六"};// 判断是否为闰年
int isLeapYear(int year) {return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}// 计算指定日期是星期几
int getWeekday(int year, int month, int date) {int days = 0;int leap = isLeapYear(year);for (int i = 0; i < month - 1; i++) {days += dateofmonth[leap][i];}days += date;return ((year - 1) + (year - 1) / 4 - (year - 1) / 100 + (year - 1) / 400 + days) % 7;
}// 打印指定年份的日历
void printCalendar(int year, int month_a, int month_b) {printf("\n\n\n\t—————————————%d 年日历—————————————\n\n\n", year);for (int i = month_a - 1; i < month_b; i++) {int firstWeekday = getWeekday(year, i + 1, 1);int daysInMonth = dateofmonth[isLeapYear(year)][i];// 打印月份名称printf("\t%-8s\t\t\t\t\t%6s\n", month1[i], month2[i]);printf("\t______________________________________________________\n\t  ");// 打印星期名称for (int j = 0; j < 7; j++) {printf("%s\t", week[j]);}printf("\n\n");printf("\t# ");// 打印空白以对齐第一个日期if (firstWeekday > 0) {for (int n = 0; n < firstWeekday; n++) {printf("  \t");}printf(" ");}// 打印日期for (int k = 1; k <= daysInMonth; k++) {if (firstWeekday == 7) {printf("\n\t# ");firstWeekday = 0;}if (firstWeekday == 6) {printf("%2d #", k);} else {printf("%2d\t ", k);}firstWeekday++;}// 补齐行尾if (firstWeekday < 6) {while (firstWeekday++ != 6) {printf("  \t");}printf("    #");} else if (firstWeekday == 6) {printf("   #");}printf("\n\t______________________________________________________\n");printf("\n\n\n\n\n");}
}// 查询指定日期是星期几
void queryWeekday() {int year, month, day;printf("请输入要查询的日期 年 月 日(2024 1 1):");scanf("%d %d %d", &year, &month, &day);printf("\n\n查询结果如下:\n\n%d年%d月%d日是星期%s\n\n\n\n\n", year, month, day, week[getWeekday(year, month, day)]);
}// 查询指定年份是否为闰年
void queryLeapYear() {int year;printf("请输入要查询的年份(2024):");scanf("%d", &year);printf("\n\n查询结果如下:\n\n");if (isLeapYear(year)) {printf("%d是闰年\n", year);} else {printf("%d不是闰年\n", year);}
}// 查询指定月份的最大天数
void queryDaysInMonth() {int year, month;printf("请输入要查询的月份(2024 1):");scanf("%d %d", &year, &month);printf("\n\n查询结果如下:\n\n");int leap = isLeapYear(year);printf("%d年%d月有%d天\n\n", year, month, dateofmonth[leap][month - 1]);
}// 主菜单函数
void showMenu() {printf("         万年历查询系统\n\n");printf("**************************************\n");printf("1:查询某年某月某日是星期几\n");printf("2:查询某年是否是闰年\n");printf("3:打印某年的日历\n");printf("4.查询某月的最大天数\n");printf("5:退出\n");printf("**************************************\n");printf("\n请选择: ");
}int main() {int choice, year;while (1) {showMenu();scanf("%d", &choice);printf("\n");switch (choice) {case 1:queryWeekday();break;case 2:queryLeapYear();break;case 3:printf("请输入要打印的年份(2024):");scanf("%d", &year);printCalendar(year, 1, 12);break;case 4:queryDaysInMonth();break;case 5:return 0;default:printf("\n\n\t输入错误,请重新输入\n\n\n\n");}}return 0;
}

三、主要问题

  1. 代码冗余与重复
    逻辑重复:在多个函数中都存在对闰年判断的逻辑调用,如 getWeekday、printCalendar、queryDaysInMonth 等函数,虽然调用的是同一个 isLeapYear 函数,但多次调用会造成一定的代码冗余。
    2.错误处理
    输入验证:代码中缺乏对用户输入的验证,例如在 queryWeekday、queryLeapYear 等函数中,用户输入的日期可能不符合实际情况(如月份超出 1 - 12 的范围),但代码没有进行相应的验证和处理,可能会导致程序出现异常。
    3.可读性与可维护性
    变量命名:部分变量命名不够清晰,例如在 getWeekday 函数中,days 变量虽然能表达其存储的是天数,但没有明确说明是从哪个时间点开始计算的天数,降低了代码的可读性。
    注释不足:虽然代码中有一些注释,但整体注释不够详细,特别是一些关键逻辑部分,如计算星期几的公式,没有详细解释,不利于后续的维护和扩展。
    代码结构:代码整体结构较为复杂,函数内部的逻辑较多,例如 printCalendar 函数中包含了打印月份名称、星期名称、日期以及处理节假日等多个功能,代码过长,可将一些功能拆分成更小的函数,提高代码的可维护性。
    四、优化
    1.添加节假日显示
点击查看代码
// 打印指定年份的日历
void printCalendar(int year, int month_a, int month_b) {printf("\n\n\n\t—————————————%d 年日历—————————————\n\n\n", year);for (int i = month_a - 1; i < month_b; i++) {int firstWeekday = getWeekday(year, i + 1, 1);int daysInMonth = dateofmonth[isLeapYear(year)][i];// 打印月份名称printf("\t%-8s\t\t\t\t\t%6s\n", month1[i], month2[i]);printf("\t______________________________________________________\n\t  ");// 打印星期名称for (int j = 0; j < 7; j++) {printf("%s\t", week[j]);}printf("\n\n");printf("\t# ");// 打印空白以对齐第一个日期if (firstWeekday > 0) {for (int n = 0; n < firstWeekday; n++) {printf("  \t");}printf(" ");}// 打印日期for (int k = 1; k <= daysInMonth; k++) {if (firstWeekday == 7) {printf("\n\t# ");firstWeekday = 0;}int isHoliday = 0;for (int h = 0; h < sizeof(holidays) / sizeof(holidays[0]); h++) {if (holidays[h][0] == i + 1 && holidays[h][1] == k) {isHoliday = 1;printf("\033[31m%2d(%s)\033[0m\t ", k, holiday_names[holidays[h][2] - 1]);break;}}if (!isHoliday) {if (firstWeekday == 6) {printf("%2d #", k);} else {printf("%2d\t ", k);}}firstWeekday++;}// 补齐行尾if (firstWeekday < 6) {while (firstWeekday++ != 6) {printf("  \t");}printf("    #");} else if (firstWeekday == 6) {printf("   #");}printf("\n\t______________________________________________________\n");printf("\n\n\n\n\n");}
}

2.添加生肖和星座查询

点击查看代码
// 查询指定日期是星期几
void queryWeekday() {int year, month, day;printf("请输入要查询的日期 年 月 日(2024 1 1):");scanf("%d %d %d", &year, &month, &day);printf("\n\n查询结果如下:\n\n%d年%d月%d日是星期%s\n", year, month, day, week[getWeekday(year, month, day)]);// 显示星座int constellation_index;if ((month == 1 && day >= 20) || (month == 2 && day <= 18)) {constellation_index = 1;} else if ((month == 2 && day >= 19) || (month == 3 && day <= 20)) {constellation_index = 2;} else if ((month == 3 && day >= 21) || (month == 4 && day <= 19)) {constellation_index = 3;} else if ((month == 4 && day >= 20) || (month == 5 && day <= 20)) {constellation_index = 4;} else if ((month == 5 && day >= 21) || (month == 6 && day <= 20)) {constellation_index = 5;} else if ((month == 6 && day >= 21) || (month == 7 && day <= 22)) {constellation_index = 6;} else if ((month == 7 && day >= 23) || (month == 8 && day <= 22)) {constellation_index = 7;} else if ((month == 8 && day >= 23) || (month == 9 && day <= 22)) {constellation_index = 8;} else if ((month == 9 && day >= 23) || (month == 10 && day <= 22)) {constellation_index = 9;} else if ((month == 10 && day >= 23) || (month == 11 && day <= 21)) {constellation_index = 10;} else if ((month == 11 && day >= 22) || (month == 12 && day <= 21)) {constellation_index = 11;} else {constellation_index = 0;}printf("星座是:%s\n", constellations[constellation_index]);// 显示生肖int zodiac_index = (year - 1900) % 12;printf("生肖是:%s\n\n\n\n", zodiacs[zodiac_index]);
}

3.倒计时功能

点击查看代码
// 倒计时功能
void countdown() {int year1, month1, day1, year2, month2, day2;printf("请输入当前日期 年 月 日(2024 1 1):");scanf("%d %d %d", &year1, &month1, &day1);printf("请输入目标日期 年 月 日(2024 1 1):");scanf("%d %d %d", &year2, &month2, &day2);int days1 = 0, days2 = 0;for (int y = 1900; y < year1; y++) {days1 += isLeapYear(y) ? 366 : 365;}int leap1 = isLeapYear(year1);for (int m = 0; m < month1 - 1; m++) {days1 += dateofmonth[leap1][m];}days1 += day1;for (int y = 1900; y < year2; y++) {days2 += isLeapYear(y) ? 366 : 365;}int leap2 = isLeapYear(year2);for (int m = 0; m < month2 - 1; m++) {days2 += dateofmonth[leap2][m];}days2 += day2;int diff = days2 - days1;if (diff > 0) {printf("\n距离 %d年%d月%d日 还有 %d 天\n\n\n", year2, month2, day2, diff);} else if (diff < 0) {printf("\n %d年%d月%d日 已经过去 %d 天\n\n\n", year2, month2, day2, -diff);} else {printf("\n今天就是 %d年%d月%d日\n\n\n", year2, month2, day2);}
}

4.对代码的优化和精简

点击查看代码
#include <stdio.h>// 每月天数,[0]平年 [1]闰年
int dateofmonth[2][12] = {{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
const char *month1[] = {"January", "February", "March", "April", "May", "June","July", "August", "September", "October", "November", "December"};
const char *month2[] = {"一月", "二月", "三月", "四月", "五月", "六月","七月", "八月", "九月", "十月", "十一月", "十二月"};
const char *week[7] = {"日", "一", "二", "三", "四", "五", "六"};
const int holidays[][3] = {{1, 1, 1}, {2, 14, 2}, {3, 8, 3}, {4, 1, 4}, {5, 1, 5},{6, 1, 6}, {9, 10, 7}, {10, 1, 8}, {12, 25, 9}};
const char *holiday_names[] = {"元旦", "情人节", "妇女节", "愚人节", "劳动节","儿童节", "教师节", "国庆节", "圣诞节"};
const char *constellations[] = {"摩羯座", "水瓶座", "双鱼座", "白羊座", "金牛座", "双子座","巨蟹座", "狮子座", "处女座", "天秤座", "天蝎座", "射手座", "摩羯座"};
const int constellation_bounds[12] = {20, 19, 21, 20, 21, 22, 23, 23, 23, 24, 23, 22};
const char *zodiacs[] = {"鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪"};// 判断闰年
int isLeapYear(int y) { return (y % 4 == 0 && y % 100 != 0) || (y % 400 == 0); }// 计算星期
int getWeekday(int y, int m, int d) {int days = d;for (int i = 0; i < m - 1; i++) days += dateofmonth[isLeapYear(y)][i];return (y - 1 + (y - 1) / 4 - (y - 1) / 100 + (y - 1) / 400 + days) % 7;
}// 打印日历
void printCalendar(int y) {printf("\n\n\n\t—————————————%d 年日历—————————————\n\n\n", y);for (int m = 0; m < 12; m++) {int first = getWeekday(y, m + 1, 1), days = dateofmonth[isLeapYear(y)][m];printf("\t%-8s\t\t\t\t\t%6s\n", month1[m], month2[m]);printf("\t______________________________________________________\n\t  ");for (int i = 0; i < 7; i++) printf("%s\t", week[i]);printf("\n\n\t# ");for (int i = 0; i < first; i++) printf("  \t");for (int d = 1; d <= days; d++) {if ((first + d - 1) % 7 == 0) printf("\n\t# ");int isHoliday = 0;for (int h = 0; h < sizeof(holidays) / sizeof(holidays[0]); h++)if (holidays[h][0] == m + 1 && holidays[h][1] == d) {isHoliday = 1;printf("\033[31m%2d(%s)\033[0m\t ", d, holiday_names[holidays[h][2] - 1]);break;}if (!isHoliday) printf("%2d\t ", d);}printf("\n\t______________________________________________________\n\n\n\n\n");}
}// 查询星期、星座、生肖
void queryWeekday() {int y, m, d;printf("请输入要查询的日期 年 月 日(2024 1 1):");scanf("%d %d %d", &y, &m, &d);int w = getWeekday(y, m, d), c = (m - 1 + (d < constellation_bounds[m - 1] ? 0 : 1)) % 12, z = (y - 1900) % 12;printf("\n\n查询结果如下:\n\n%d年%d月%d日是星期%s\n星座是:%s\n生肖是:%s\n\n\n\n", y, m, d, week[w], constellations[c], zodiacs[z]);
}// 查询闰年
void queryLeapYear() {int y;printf("请输入要查询的年份(2024):");scanf("%d", &y);printf("\n\n查询结果如下:\n\n%d %s闰年\n\n", y, isLeapYear(y) ? "是" : "不是");
}// 查询月最大天数
void queryDaysInMonth() {int y, m;printf("请输入要查询的月份(2024 1):");scanf("%d %d", &y, &m);printf("\n\n查询结果如下:\n\n%d年%d月有%d天\n\n", y, m, dateofmonth[isLeapYear(y)][m - 1]);
}// 倒计时
void countdown() {int y1, m1, d1, y2, m2, d2;printf("请输入当前日期 年 月 日(2024 1 1):");scanf("%d %d %d", &y1, &m1, &d1);printf("请输入目标日期 年 月 日(2024 1 1):");scanf("%d %d %d", &y2, &m2, &d2);int days1 = 0, days2 = 0;for (int y = 1900; y < y1; y++) days1 += isLeapYear(y) ? 366 : 365;for (int m = 0; m < m1 - 1; m++) days1 += dateofmonth[isLeapYear(y1)][m];days1 += d1;for (int y = 1900; y < y2; y++) days2 += isLeapYear(y) ? 366 : 365;for (int m = 0; m < m2 - 1; m++) days2 += dateofmonth[isLeapYear(y2)][m];days2 += d2;int diff = days2 - days1;printf("\n%s %d年%d月%d日 %s %d 天\n\n\n",diff > 0 ? "距离" : diff < 0 ? "" : "今天就是",y2, m2, d2,diff > 0 ? "还有" : diff < 0 ? "已经过去" : "",diff > 0 ? diff : -diff);
}// 主菜单
void showMenu() {printf("         万年历查询系统\n\n");printf("**************************************\n");printf("1:查询某年某月某日是星期几\n");printf("2:查询某年是否是闰年\n");printf("3:打印某年的日历\n");printf("4:查询某月的最大天数\n");printf("5:倒计时功能\n");printf("6:退出\n");printf("**************************************\n");printf("\n请选择: ");
}int main() {int choice, year;while (1) {showMenu();scanf("%d", &choice);printf("\n");switch (choice) {case 1: queryWeekday(); break;case 2: queryLeapYear(); break;case 3: printf("请输入要打印的年份(2024):"); scanf("%d", &year); printCalendar(year); break;case 4: queryDaysInMonth(); break;case 5: countdown(); break;case 6: return 0;default: printf("\n\n\t输入错误,请重新输入\n\n\n\n");}}return 0;
}

五、实现效果



6、总结
难点
1.节假日显示处理
难点:要在日历中准确显示节假日,需要对每个日期进行判断,并且要考虑到不同年份的情况。同时,为了增强显示效果,使用了 ANSI 转义序列来设置节假日日期的颜色,这涉及到对控制台输出格式的控制。
耗时原因:需要设计合理的数据结构来存储节假日信息,并且要编写循环逻辑来遍历每个日期并检查是否为节假日。此外,还要处理不同操作系统和终端对 ANSI 转义序列的支持情况,确保显示效果的一致性。
2.代码优化与精简
难点:在保证代码功能完整的前提下,要对代码进行优化和精简,减少代码冗余,提高代码的可读性和可维护性。这需要对代码结构有深入的理解,并且要掌握一些优化技巧,如函数封装、变量命名规范等。
耗时原因:需要反复审查代码,找出可以优化的部分,并进行多次修改和测试,以确保优化后的代码仍然能够正常工作。
思考
1.代码重构和优化
逆向工程的结果可以为代码重构和优化提供依据。通过分析代码的结构和逻辑,可以找出可以改进的部分,并进行相应的重构和优化。例如,可以将一些重复的代码提取成独立的函数,减少代码冗余;可以优化循环逻辑,提高代码的执行效率。
2.发现潜在问题
逆向工程可以帮助发现代码中存在的潜在问题。例如,在分析代码时,可以发现代码中缺乏输入验证的问题,这可能会导致程序在接收到非法输入时出现异常。此外,还可以发现代码中存在的性能问题,如重复计算、循环嵌套过深等,这些问题可能会影响程序的运行效率。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/890404.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

逆向软件设计和开发---学生信息管理程序

一、来源 源代码来自同学大一上学期C语言大作业 二、运行环境 Dev-C++ 6.3 三、源代码及运行结果 1.源代码点击查看代码 #include <stdio.h> #include <stdlib.h> #include <string.h>#define MAX_NAME_LENGTH 20 #define MAX_SCORE_COUNT 5// 学生信息结构体…

在鹅厂做java开发是什么体验

离职已有好几个月,准备写一篇关于之前在腾讯做Java开发的经历,现在来谈谈在Java领域里,在腾讯做Java开发的体验。随便写写别较真。首先,介绍一下腾讯里与Java相关的部门。主要有CDG(云与智慧产业事业群)中的腾讯广告和FIT(金融科技事业群)理财通。其他部门则包括TEG中的…

软件二次开发

软件来源:舍友期末大作业 软件运行环境:dev C++ 软件运行图: 软件伸缩代码图: 问题:菜单只会出现一次,在多次操作之后菜单会被顶走,届时用户只能依照记忆操作系统 更改的代码: 在循环执行选项的代码部分增加了菜单的输出 更改后的代码运行:

换根dp

概念 换根 \(dp\) ,又被称为二次扫描,是属于树形 \(dp\) 的一类但比一般树形dp更难。 特点通常是没有指定根结点,且根结点的变化会对一些值产生影响。通常需要两次 \(dfs\) ,第一次 \(dfs\) 预处理信息,第二次 \(dfs\) 开始换根动态规划。求解的答案通常需要结合所有相连的…

千锋教育MyBatisPlus全套课程,简单快速一套精通MyBatisPlus框架(代码生成器_引入_使用)

https://www.bilibili.com/video/BV1aa4y1A7iN?spm_id_from=333.788.videopod.episodes&vd_source=0d7b1712ce42c1a2fa54bb4e1d601d78代码生成器_引入_使用 https://github.com/godmaybelieve

【PLSQL】使用PLSQL查看创表SQL踩坑

背景 通过PL/SQL Developer的View SQL查看表的创表语句,结果发现创表语句少了字段 可能原因PL/SQL Developer 的对象浏览器会缓存元数据信息以提高性能。如果修改表结构后未手动刷新,工具可能继续展示缓存中的旧元数据。 Oracle 的数据字典视图(如 USER_TAB_COLUMNS)本身是…

从 0 到 Offer:Dynamics 365 CRM 学员的普华永道逆袭之路

在竞争激烈的就业市场中,如何才能脱颖而出,收获理想的工作?李先顺(化名)的经历或许能给我们带来深刻的启示。这位出身普通高校信息管理专业的应届毕业生,通过在爱码士IT培训www.aimashi365.com机构的报名和培训,凭借着对 Dynamics 365 CRM 技术的深入学习和实践,成功入…

本地?线上?分布式系统前后端架构、部署、联调指南,突破技术

“ 引言:对于常见的BS架构系统,程序员如何进行本地或者线上环 境联调,这有助于提高个人工作效率,站在更高的角度审视系统, 从此以后再无惧Bug,让你早干完活,早摸鱼🐟,早下班。 对于Java初学者,或者是三年工作经验的“新手” ,希望此文对你有所裨益! -- 诗经有云,…

Spring AI 学习之路 快速上手

随着人工智能(AI)技术的迅速发展,越来越多的开发者开始关注如何在自己的应用中集成 AI 功能。Spring 框架作为一种流行的 Java 开发框架,提供了强大的支持来构建现代应用程序。本文将为你介绍如何快速上手 Spring AI,帮助你在项目中轻松集成 AI 功能。什么是 Spring AI? …

【PWN】初识Orw

例题:NPCCTF - Ooooorw发现开启了沙箱,禁用了execve函数,所以只能利用open,read,write函数来进行输出flag from pwn import *file = ./pwnlibc = ELF(./libc.so.6)i = 0if i == 1: io = process(file)else: io = remote(175.27.249.18,32438)elf = ELF(file)context…

洛谷2025省选模拟赛D1T1“Ball” 题解

洛谷2025省选模拟赛D1T1“Ball” 题解首先可以写出一个暴力的 dp : 令 \(f_{i,j}\) 表示有 \(i\) 个选了一次的球和 \(j\) 个选了大于一次的球的期望答案,有等式: \[f_{i,j}=\frac jnf_{i,j}+\frac{n-i-j}nf_{i+1,j}+\frac in f_{i-1,j+1} \]进一步得 \(f_{i,j}=\frac{n-i-j…

[计算机网络/网络抓包/以太网] `.pcap` 数据报文存储格式

序:一份以太网报文概述:.pcap 数据报文存储格式 简介.pcap文件:一种常用的数据报文存储格式,主要用于网络数据包的捕获和存储。pcap文件格式由PCAP库提供,支持将网络上的所有数据包保存到文件中,并可以从文件中读取数据包。 pcap文件通常由文件头和数据包头组成,每个数据…