温馨提示
程序语言: C、 C++、C#、Python(红色字体 表示本课设使用的 程序设计语言 )
图形功能选项: Win32 控制台程序(黑框、文本界面) 、Win32 程序、 MFC 、 WinForm 、 DirectX10 (黑体标明 表示本课设的 程序图形类别 ,默认为非图形界面 Win32 控制台程序 )
数据结构:基础类型、 数组、链表、双向链表、搜索树(非平衡二叉树)
、平衡二叉树、
链表与平衡二叉树相结合、堆栈、队列、串、图( 黑体标明 表示本课设使用的 数据结构 )
C++语言项: STL 库(黑体标明 表示使用 C++的 STL 库)
编译环境: Windows 7 64 位旗舰版( Linux 及其他环境 请谨慎下载 )
集成开发环境: Visual C++ 6.0、DEVC++ 、CodeBlocks、Visual Studio 2015 均可通过编译。(若无法通过编译运行 ,则会用 浅蓝色字体 表示)
分多头文件 编译: 否(所有代码基本都包含在 一个文件内 ,如需试验头文件功能,请自行参考相关文献)
内容说明:
1、课设题目及预览内容
将在第二页开始展示。
2、代码行数: 333 行
3、目录 所示内容,本文基本涵盖, 如无内容,会在本页进行说明 。
4、附录 绝对包含 用户使用手册 及程序完整源代码和详细注释 。
5、如需下载 其他 头文件(例如 DirectX 需另行配置),本文会在此进行说明。
6、本文撰写内容仅供学习参考 ,另外,由于本人水平有限,编写之处难免存在错误
和纰漏,恳请各位老师或同学批评指正。
题目:万年历显示
功能要求:
(1) 输入一个年份,输出是在屏幕上显示该年的日历。假定输入的年份在
间。
(2) 输入年月,输出该月的日历。
(3) 输入年月日,输出距今天还有多少天,星期几,是否是公历节日。
1940-2040 年之
运行截图:
功能(一):
功能(二):
功能(三):
课程设计报告
课
题:
学专
院:业:
学生姓名:学
号:
指导老师:
20XX年 XX月 XX日
目录
摘要 ...................................................................................................................................................... 1 1 总体设计 ........................................................................................................................................... 2
1.1 需求分析 ................................................................................................................................ 2 1.2 功能流程图 ............................................................................................................................ 2 1.3 功能模块图 ............................................................................................................................ 3
2 详细设计 ........................................................................................................................................... 4
2.1 数据结构 ................................................................................................................................ 4 2.2 函数功能设计 ........................................................................................................................ 4
3 调试分析 ........................................................................................................................................... 7
3.1 程序测试 ................................................................................................................................ 7 3.2 程序缺陷 ............................................................................................................................... 9
4 总结与体会 ..................................................................................................................................... 10 参考文献 ............................................................................................................................................ 11 附录 .................................................................................................................................................... 12
摘要
万年历的主要功能是通过
C 语言编程实现查询某年的日历情况,并且可以查询某年月的
日历情况,还可以对某年月日进行计算距今的天数和判断是否为公历节日,其功能和代码满
足人性化设计和良好的编程规范要求。
关键词: 万年历, C 语言编程,人性化设计
1
1 总体设计
1.1 需求分析
系统将以用户输入的信息进行功能的选择,提供某年日历的输出、某年某月日历的输出
和距今天数的输出及节假日的判断这大三功能。
1.2 功能流程图
本程序主要通过获取屏幕输入,然后进行字符串处理,选择相应的功能执行,最后打印输出信息。功能流程图如下:
开始
输入
处理输入信息
判断年月日
年月日运算,计算
距今的天数
年月运算,准备打 印某年某月日历
年运算,准备打印
某年日历
输出
结束
图 1.1 功能流程图
2
1.3 功能模块图
打印某年日历
模块
打印某年某月
提示信息
日历模块
计算距今天数和
判断节日模块
图 1.2 功能模块图
3
2 详细设计
2.1 数据结构
建立日历信息结构体,结构体成员变量包括月末、月初星期几、屏幕信息左半边日历是
否打印完毕。
typedef
struct calendar {
int month_end; // 月末最后一天的数字
int first_day; // 月初星期几 0 周日 1 周一 ......
int
printFinished;
// 打印完毕则为 1,没打印完成则为 0
} Calendar ;
建立年月日信息结构体,结构体成员变量包括年份、月份、天数。
typedef struct date {
int year; int month; int day; } Date ;
2.2 函数功能设计
本万年历系统主要分为三大功能,分别是打印某年日历、打印某年某月日历、打印距今天数和判断是否节假日,故分别设计三个函数实现三大功能,如下所示。
void firstFun( int year , Calendar cal []); // 第一功能
void secondFun( int year , int month , Calendar cal []);
// 第二功能
void thirdFun(
int year , int
month , int
day ); // 第三功能
各程序流程图如下:
4
firstFun()
函数
开始
判断是否打印了 6 和 12 月份的日历
是
否
打印某月日历
结束
图 2.1 程序流程图(一)
secondFun()
开始
函数
判断是否月末的
是
天数
否
打印某月某日的日历
结束
图 2.2 程序流程图(二)
5
thirdFun() 函数
开始
计算距今天数
判断是否
节假日
打印信息
结束
图 2.3 程序流程图(三)
6
3 调试分析
3.1 程序测试
运行程序之后,会进入主界面,如图
3.1 所示。
图 3.1 主界面图
随后,可分别通过输入年、年月、年月日实现三个功能的输出,具体如图
3.2~3.4 所示。
图 3.2 打印某年日历图
7
图 3.3 打印某年月日历图
图 3.4 计算距今天数图
8
3.2 程序缺陷
1、该程序每次运行,只能执行一次,不能重复选择功能,属于设计缺陷。
2、对年份的不规范输入,可能出现与预期结果不一致的情况,如图
3.5 所示,理论应该
输出 12345 年的日历,然而只是输出了 12345 年 5 月的日历,属于程序漏洞。
图 3.5 BUG 展示图
9
4 总结与体会
这个课程设计的难度在于打印输出日历,在设计过程中遇到问题,可以说是困难重重,
因为毕竟是第一次做的,难免会遇到各种各样的问题,同时在设计过程中我也发现了自己的
不足之处,对以前所学过的知识理解的不够深刻, 掌握的不够牢固。 通过这次课程设计之后,
我觉得以前学过的知识要重新温习才能够达到查漏补缺的效果。我会在今后的日子里,努力
学好程序设计,成为一名出色的工程师。
最后,这次的课程设计终于得以圆满完成。 其中,我在设计中也遇到了许许多多的问题,
但在老师的指导和同学们的帮助下得到了解决,总的来说还不是这个程序还不是很完善,但
我不会放弃继续完善这份程序,我会在课余时间里继续修改完善这份程序。
在此,感谢所有帮助过我的同学和指导老师。
10
参考文献
[1] 谭浩强著 .C 程序设计(第四版) . 北京:清华大学出版社, 2010 [2] 林锐著 . 高质量 C 编程指南 . 北京:电子工业出版社, 2001 [3]Stephen A.Maguire.
编程精粹:编写高质量
C 语言代码 . 人民邮电出版社,
2009
11
附录
用户使用手册
1、根据屏幕提示,输入即可。
2、输入年份,例如 2018 年,则会打印 2018 年的日历。
3、输入年月,例如 2018 10(也可以尝试其他的分隔符,例如
2018,10),则会打印 2018
年 10 的日历。
4、输入年月日,例如 2018 10 1(同上),则会输出距今的天数和输出具体的节假日。
程序源代码
#include isPrime (year) ((year%4==0&&year%100!=0)||(year%400==0)) TWELVEMONTH12 // 数组大小 // 消除 Visual Stdio // 宏函数,判断是否为闰年 #define #pragma warning ( disable :4996) 编译环境的安全警告,其他编译环境可删除 //------------------------------ //---------- 结构体定义区 --------- //------------------------------ typedef struct calendar { // 月末最后一天的数字 // 月初星期几 0 周日 1 周一 ...... // 打印完毕则为 1,没打印完成则为 0 int month_end; int first_day; int printFinished; } Calendar ; typedef { struct date int year; int month; int day; } Date ; //---------------------------- //---------- 函数声明区 --------- //---------------------------- void judgmentLeapYear( int year , Calendar * cal ); 12 // 判断闰年 int calculateWeeks( void firstFun( int int y, int m, int d); // 计算该年月日是周几 // 第一功能 year , Calendar year , int year , int cal []); void secondFun( int void thirdFun( month , Calendar cal []); // 第二功能 int struct month , int day ); // 第三功能 date maxdate ); // 计算日期之间的间隔天数 int dateDiff( date mindate , struct int main( void ) { Calendar cal[ TWELVEMONTH] = { { 31 }, //1 月 { 28 }, //2 月 { 31 }, //3 月 { 30 }, //4 月 { 31 }, //5 月 { 30 }, //6 月 { 31 }, //7 月 { 31 }, //8 月 { 30 }, //9 月 { 31 }, //10 月 { 30 }, //11 月 { 31 } //12 月 }; // 初始化月份 int year = 2000, month = 0, day = 0; int fun = 0; char calendar[30] = { '\\0' }; // 用来处理输入 printf( \"Please input the your whose calendar you want to know:\" fgets(calendar, 30, stdin ); year = atoi(calendar); // 得到年份 if (calendar[4] != '\\0' ) month = atoi(calendar + 4); // 得到月份 if (strlen(calendar) >= 8) day = atoi(calendar + strlen(calendar) - 2); if (0 != year && 0 == month && 0 == day) fun = 1; else fun = 0 == day ? 2 : 3; judgmentLeapYear(year, &cal[1]); / / 调整闰年平年 2月的天数 int i = 0; for (i = 0; i < TWELVEMONTH; i++) 13 ); cal[i].first_day = calculateWeeks(year, i + 1, 1); switch (fun) { case 1:firstFun(year, cal); case 2:secondFun(year, month, cal); case 3:thirdFun(year, month, day); } break ; break ; break ; return 0; } void judgmentLeapYear( { int year , Calendar * cal ) if ((( year % 4 == 0) && ( cal ->month_end = 29; else year % 100 != 0)) || ( year % 400 == 0)) cal ->month_end = 28; } int calculateWeeks( { int c, w, y; int year , int month , int day ) y = year % 100; // 年 c = year / 100; if ( month == 1 || y--; 如2015 即年是 15 年 如2015 即 20 // 年份前两位 month == 2) { // 判断月份是否为 1或2 month += 12; // 某年的 1、2月要看作上一年的 13、 14月来计算 } w = y + y / 4 + c / 4 - 2 * c + 13 * ( while (w < 0) w += 7; w %= 7; return w; } // 确保余数为正 month + 1) / 5 + day - 1; // 蔡勒公式 void firstFun( { printf( int year , Calendar cal []) \"|===================The Calendar of Year %d ====================|\\n\" , year ); int month = 1; for (month = 1; month <= TWELVEMONTH/2; month++) { printf( \"| %d SUN MON TUEWED THU FRI SAT %2d SUN MON TUE WEDTHU FRI SAT |\\n\" , month, month + 6); int right = 1, left = 1; 14 int i = 0; for (right = 1, left = 1; 1; left++) { if (1 == left) { printf( \"| \" / / 左边首日打印 ); for (i = 0; i < calculateWeeks( printf( printf( \" \" );; year , month, left); i++) \"%4d\" , left); if (6 == calculateWeeks( printf( } } \" \" ); year , month, left)) { // 既是首日也是周六 else if (left == printf( cal [month - 1].month_end) { // 左边月末打印 \"%4d\" , left); year , month, left); i++) for (i = 0; i < 6 - calculateWeeks( printf( printf( \" \" \" \" ); ); cal [month - 1].printFinished = 1; } // 月末,则表示左边日历打印完毕 else calculateWeeks( left (6 == year , month, left) && <= cal [month - 1].month_end) if / 左边日历的周六 , 则开始打印右边的日历 printf( \"%4d\" , left); for (i = 0; i < 6 - calculateWeeks( printf( printf( } else if (1 == cal [month - 1].printFinished) { // 左边打印完毕则补齐空格 \" \" \" \" ); ); year , month, left); i++) for (i = 0; i < 8; i++) printf( printf( } else printf( \"%4d\" , left); \" \" ); \"\" ); if (6 == calculateWeeks( cal [month - 1].printFinished) { for (;; right++) { if (1 == right) { year , month, left) && left <= cal [month - 1].month_end || // 右边首日打印 year , month + 6, right); i++) for (i = 0; i < calculateWeeks( printf( printf( \" \" );; \"%4d\" , right); 15 if (6 == calculateWeeks( 六 printf( right++; break ; } } \" |\\n| \" ); year , month + 6, right)) { // 既是首日也是周 else if (right == printf( cal [month - 1 + 6].month_end) { // 右边月末打印 \"%4d\" , right); year , month + 6, right); i++) for (i = 0; i < 6 - calculateWeeks( printf( printf( \" \" ); ); \" |\\n| \" cal [month - 1 + 6].printFinished = 1; right++; break ; } // 月末,则表示右边日历打印完毕 else if (6 == calculateWeeks( - 1 + 6].month_end) { year , month + 6, right) && right <= cal [month // 右边日历的周六 , 则开始打印左边的日历 printf( right++; break ; } \"%4d |\\n| \" , right); else if ( cal [month - 1 + 6].printFinished) { for (i = 0; i < 7; i++) printf( printf( right++; break ; } else printf( } \"%4d\" , right); \" \" ); ); // 右边打印完毕则补齐空格 \" |\\n| \" } if ( cal [month - 1].printFinished&& putchar( '\\r' break ; } } } putchar( '|' ); int i = 0; for (i = 0; i < 65; i++) putchar( '=' ); ); // cal [month - 1 + 6].printFinished) { 将光标跳到本行的开头,消除多余的打印字符 16 putchar( '|' ); putchar( '\\n' ); } void secondFun( int { printf( printf( year , int month , Calendar cal []) \"|======The Year %d Month %d=====|\\n\" \"| %d SUN MON TUE WED THU FRI SAT |\\n\" , year , month ); , month ); int i = 1, j = 1; for (i = 1; i <= if (1 == i) { printf( \"| \" cal [ month - 1].month_end; i++) { // 首日打印 ); year , month , i); j++) for (j = 0; j < calculateWeeks( printf( printf( \" \" ); \"%4d\" , i); if (6 == calculateWeeks(year , month , i)) { // 既是首日也是周六 printf( } \" |\\n| \" ); } else if (6 == calculateWeeks( printf( } \"%4d |\\n| \" , i); year , month , i)) { // 周六换行 else if (i == printf( cal [ month - 1].month_end) { \"%4d\" , i); // 月末 for (j = 0; j < 6 - calculateWeeks( printf( printf( } else printf( } \"%4d\" , i); \" \" ); ); year , month , i); j++) \" |\\n\" putchar( '\\r' ); putchar( '|' ); for (i = 0; i < 32; i++) putchar( '=' ); putchar( '|' ); putchar( '\\n' ); } void thirdFun( { time_t t; int year , int month , int day ) 17 struct tm * timeinfo; Date d1 = { year , month , day }; Date d2; char ch[20] = { '\\0' }; // 用于存储周几 char festival[20] = { '\\0' };// 用于存储节日 int iDayNum = 0; time(&t); // 获取今天的日期 timeinfo = localtime(&t); d2.year = timeinfo->tm_year + 1900; d2.month = timeinfo->tm_mon + 1; d2.day = timeinfo->tm_mday; iDayNum = (dateDiff(d1, d2)); switch (calculateWeeks(d1.year, d1.month, d1.day)) { case 0:strcpy(ch, \"Sunday\" ); break ; case 1:strcpy(ch, \"Monday\" ); break ; case 2:strcpy(ch, \"Tuesday\" ); break ; case 3:strcpy(ch, \"Wednesday\" ); break ; case 4:strcpy(ch, \"Thursday\" ); break ; case 5:strcpy(ch, \"Friday\" ); break ; case 6:strcpy(ch, \"Saturday\" ); break ; } if (1 == d1.month && 1 == d1.day) strcpy(festival, \"New year's Day\" ); // 元旦 else if (3 == d1.month && 8 == d1.day) strcpy(festival, \"International Women's Day\" ); else if (3 == d1.month && 12 == d1.day) strcpy(festival, \"Arbor Day\" ); // 植物节 else if (4 == d1.month && 5 == d1.day) strcpy(festival, \"Qingming Festival\" ); // 清明节else if (5 == d1.month && 1 == d1.day) strcpy(festival, \"Labor Day\" ); // 劳动节 else if (5 == d1.month && 4 == d1.day) strcpy(festival, \"Youth Day\" ); // 青年节 else if (6 == d1.month && 1 == d1.day) strcpy(festival, \"Children's Day\" ); // 儿童节 else if (7 == d1.month && 1 == d1.day) strcpy(festival, \"Party Building\" ); // 建党节 else if (8 == d1.month && 1 == d1.day) strcpy(festival, \"Army Day\" ); // 建军节 else if (9 == d1.month && 3 == d1.day) strcpy(festival, \"Anti Japanese War Victory Day\" 18 // 国际妇女节 ); // 抗日战争胜利纪念日 else if (9 == d1.month && 10 == d1.day) strcpy(festival, \"Teachers day\" ); // 教师节 else if (10 == d1.month && 1 == d1.day) strcpy(festival, else \"National Day\" ); // 国庆节 strcpy(festival, \"No Festival\" ); / / 非节日 printf( \"The output is %d days away today, %s , %s.\\n\\n\" , iDayNum, ch, festival); } int dateDiff( { struct date mindate , struct date maxdate ) int days = 0, j, flag; const int primeMonth[][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 } }; /************************************************************************/ /* 交换两个日期函数 , 将小的日期给 mindate, 将大的日期给 maxdate */ /************************************************************************/ struct date tmp; mindate .year == mindate .year == maxdate .year&& mindate .month == if (( mindate .year> maxdate .year) || ( maxdate .year&& mindate .month> maxdate .month) || ( maxdate .month&& mindate .day> maxdate .day)) { tmp = mindate ; mindate = maxdate ; maxdate = tmp; } /************************************************************************/ /* 从mindate.year 开始累加到 maxdate.year */ /************************************************************************/ for (j = mindate .year; j< maxdate .year; ++j) days += isPrime (j) ? 366 : 365; // 如果 maxdate.year flag = 是闰年 , 则flag=1, 后面调用 primeMonth[1][12] isPrime ( maxdate .year); // 加上 maxdate.month 到1月的天数 for (j = 1; j< maxdate .month; j++) days += primeMonth[flag][j - 1]; // 减去 mindate.month 到1月的天数 flag = isPrime ( maxdate .year); mindate .month; j++) for (j = 1; j< 19 days -= primeMonth[flag][j - 1]; days = days + return days; } maxdate .day - mindate .day; 20 因篇幅问题不能全部显示,请点此查看更多更全内容