万年历程序设计-----石玉英.doc
Four short words sum up what has lifted most successful individuals above the crowd: a little bit more.-author-date万年历程序设计-石玉英万年历程序设计-石玉英 华科学院计算机系信息管理与信息系统专业程序设计综合课程设计报告 (2010/2011学年 第一学期)学生姓名: 石玉英 学生班级: 信息管理092201H学生学号: 200922040116指导教师: 荀亚玲2011年1 月 13 日目 录第一章 课程设计的目的和要求11.1 课程设计的目的11.2 课程设计的要求2第二章 课程设计任务内容32.1功能需求32.2功能模块62.2.1功能模块图62.2.2主要模块说明7第三章 详细设计说明93.1 程序设计思路93.2函数功能说明93.2.1总函数流程图103.2.2参数说明10第四章 软件使用说明13第五章 课程设计心得与体会17附录1 参考文献18附录2 源程序19万年历系统第一章 课程设计的目的和要求1.1 课程设计的目的 通过本项课程设计,可以培养独立思考、 综合运用所学有关相应知识的能力,能更好的巩固C语言程序设计课程学习的内容,掌握 工程软件设计的基本方法,强化上机动手编程能力,闯过理论与实践相结合的难关!更加了解了c语言的好处和其可用性!同时增加了同学之间的团队合作精神!更加也体会到以后在工作中团队合作的重要性和必要性! 根据课堂讲授内容,学生做相应的自主练习,消化课堂所讲解的内容;通过调试典型例题或习题积累调试C程序的经验;通过完成辅导教材中的编程题,逐渐培养学生的编程能力、用计算机解决实际问题的能力。 在学习程序设计之前,我们首先要了解程序设计的基础是什么,在学习的时候应该重点掌握什么。 其实这一问题很好回答,重点是程序设计的基本概念、方法和思维方式,其次才是程序设计语言(在本课程中就是C语言)。我们开发程序的目的是为了解决问题,而解决问题首先需要找出合适的解决方案,然后用合适的语言把方案描述出来。显然,该过程的关键是分析问题并找出解决方案,而不是描述方案。因此,程序设计课程的首要目标,是培养解决问题的基本思维方式,其次才是语言知识。 因此,同学们在学习C程序设计的时候必须树立以下观念:(1)学习思考的方法比学习语言更重要,(2)琢磨程序设计的思维模式比琢磨C语言的知识更重要,(3)培养自己的思考能力比记忆语言知识更重要。 另外,C语言本身的复杂性也是其比较难学的原因之一。C不仅可以用来开发应用程序,更可用来设计系统程序。比起其他语言,C增加的许多特点就是为了设计高质量的系统软件。显然,这些特点也增加了学习C的难度。 通过C语言课程设计,使学生了解高级程序设计语言的结构,掌握基本的程序设计过程和技巧,掌握基本的分析问题和利用计算机求解问题的能力,具备初步的高级语言程序设计能力。为后续各门计算机课程的学习和毕业设计打下坚实基础1.2 课程设计的要求 本课程设计是C语言程序设计课程实践环节的深化和延续。此次课程设计的目的是以C程序设计语言为基础,通过完成具有一定难度的课程设计题目的功能描述、总体设计、程序编写及调试工作,加深对C语言相关知识的理解与Visual C+集成开发环境的使用,重点掌握文件操作函数的熟练运用,并养成良好的程序设计习惯,提高自我分析问题、解决问题的能力,为进一步学习高级编程技术及其相关课程打下良好基础掌握面向对象程序设计的基本方法 ,熟练掌握C+编程工具 ,根据问题进行学习,拓广、深化 ,独立完成一个小型应用程序的设计、编码和测试,为以后学习软件工程打下实践基础系统说明书要求提交打印版或手写版(这是检查作业的依据)。内容包括:系统需求描述(问题描述),系统结构设计(类体系设计),类的详细设计(各类定义的基本功能,即主要数据和函数功能描述,以及类和类之间的交互),拟采用开发平台(Visual C+)作业报告:根据原有的系统设计,编码阶段的工作,整理书写作业报告,内容包括:问题描述,系统设计,使用说明,讨论, 最后提交(电子版):实验报告, 基本要求:1、要求利用C语言面向过程的编程思想来完成系统的设计;2、突出C语言的函数特征,以多个函数实现每一个子功能;3、画出功能模块图;4、进行简单界面设计,能够实现友好的交互;5、具有清晰的程序流程图和数据结构的详细定义;6、熟练掌握C语言对文件的各种操作。7、分析程序的功能要求,划分程序功能模块。8、代码的编写。定义数据结构和各个功能子函数。9、程序的功能调试;10、完成系统总结报告以及使用说明书(4)指导教师应做到教书育人。设计开始时要进行动员布置,对学生提出明确的设计任务要求及注意事项,在设计期间要每天进行辅导和检查,及时予以指导和帮助,使设计顺利进行。基层教学单位的指导教师应创造条件让学生使用计算机进行设计,培养学生的计算机应用能力。 第二章 课程设计任务内容本程序通过C语言编程实现了一个万年历,能实现基本的万年历功能。万年历的实现核心是要判断闰年和根据给定的日期计算其对应的星期,并按照合适的方式输出日历.2.1功能需求万年历能实现一些功能,主要包括以下几点:(1)日历显示功能。能根据系统日期进行初始化,如果没有任何输入,则显示系统日期所在月份的月历。 判断星期,但根据蔡勒公式,可以很容易地有年月日推断出星期:nDay=year-1+(year-1)/4-(year-1)/100+(year-1)/400+nday;w=nDay%7;其中year:要查询的年份nday:从该年的一月一日起到该天的天数w:得出的星期数,w=0表示星期天。 在打印月历时,只要知道第一天的星期,就可以依次输入后面的日期,通过定长度输出日期,在遇到某天时星期六时,就换行输出,因此可以按照月历的格式输出。对于初始输入当前月历,可以通过<time.h>中的time 和localtime函数取出系统时间进行初始化。time_t timer;struct tm* gmt;time(&timer);gmt=localtime(&timer);gmt就是一个时间结构体,可以从中取出年月日(2)日历查询、闰年判断功能。输入日期进行查询,显示查询日期所在月份的月历,还将显示所在年份是否为闰年能被4整除但不能被100整除,或者能被400整除的年份为闰年,否则为平年。日期的查询,就是直接打印改天所在月份的月历(3)参数检查功能。如果输入日期不合法,查询将被拒绝,并显示提示信息。判断日期是否合法,可以先判断年月日是否有小于0的值,月和日是否有超出最大值12和31 ,如果通过此判断合法,再判断是否时闰年,如果时闰年,则判断二月份是否满足要求,闰年二月份不能超过29天,平年二月份不能超过28天。在查询过程中,如果发现输入不合法或者不满足输入要求,则要求重新输入。(4)通过键盘操作(如:光标上、下、左、右移动键,pageup、pagedown键)调整年份、月份和日期,并显示调整后的日期及月历。捕获键盘的输入,通过两个getch();将后一个getch()的返回值付给整型或字符型k,k为相应键的ascii值,判断ascii值,就可以知道时哪个键的输入。若捕获到某键的输入,则设置相应的年或月或日的值,再进行刷性输出,就可以实现日期的调整。2.2功能模块2.2.1功能模块图本系统包括4个模块,分别是功能控制模块打印输出模块日历显示模块和键值获取模块。1、功能控制模块。该模块用于实现日期有效性检查判断是否是闰年和返回指定日期对应的日期。 2、打印输出模块。该模块主要是进行输出显示,包括打印指定个数的空格打印分隔线打印用户使用手册打印当前日期对应的星期以及打印指定的星期。3、日历显示模块。该模块是系统的核心模块,是用来显示指定日期所在月份的月历。4、键值获取模块。该模块接受键盘操作,获取键值,来进行日期调整,并调用日历显示模块中的函数来显示调整后的日历。万年历体系日历显示模块键值获取模块打印输出模块功能控制模块 帮助退出修改日期日历查询日历显示 图2-1功能模块图2.2.2主要模块说明(1)日历显示模块日历显示是系统的核心模块,它控制着日历的生成和显示。其实现流程如图所示。程序输入的是包含年月日的日期,输出month所在月份的月历,并突出显示day所在的日期和year是否是闰年的标识。程序首先根据判断year其是否是闰年,如果是则需要将该年2月份的天数设置为29天,接着判断day是否超过month所在的月份的最大天数,如果超过则显示系统日期所在的月历。然后进行星期输出的判断,如果输出的是该月的第一个星期,则判断该星期中还有几天在本月(如,该月1号是星期五,则表示该月第一个星期中只有两天在本月,星期一到星期四在上月,则星期一到星期四在本月就不输出,仅有空格表示),输出完第一周后,接着输出第二到第五(或者六)周,每周7天。在输出过程中,如果遇到了day所在的日期,则突出显示(2)键值获取模块键值获取实现的是从键盘调整日期并显示调整后的日历。系统首先 判断从键盘输入的 值,如果是右移键,表示增加月份。如果 左移键,表示减少月份。如果上移键,表示增加年份。如果下移键表示减少年份。如果上翻页键表示减少日期。如果是下翻页键表示增加日期。如果Q/q键表示查询日期,此时将输出提示信息,提示用户输入查询日期。在用户输入查询日期后,系统将调用日期检查函数对输入日期的 合法性进行检测,如果输入日期不合格,则提示错误信息并显示当前系统日期所在月的 月历;如果是 空格键表示重置,显示当前系统日期所在月的 月历;如果是Esc键表示退出系统,按此键后,系统将询问用户是否确定退出,在得到确定回答(用户输入Y/y)后将退出系统。第三章 详细设计说明3.1 程序设计思路(1)由于万年历具有以下特点:平年365天(52周+1天),闰年366天(52周+2天)。平年2月28天,闰年2月29天。(2)根据万年历以上特点进行编写 1)首先对万年历年、月、日进行编写,编写程序先定义每月的天数为28天,如月份为1、3、5、7、8、10、12就定义天数为31天反之如果月份为4、6、9、11就输出天数为30天,由上可见2月份为28天但是如果为闰年就有29天就要定义一个数组存放天数,用while循环控制。2)再对其中的星期进行编写:由于公元1月1日设为星期六,故3月1日为星期三,可以用万年3月1日星期算法(特别是那个三)由于其公式为:某年3月1日星期几=(百年%4*5天+年/4*5天+年%4+月星期表+日+2天)%7闰4百年3月1日星期算法(百年%4=0)其公式为:某年3月1日星期几=(年+年/4+月星期表+日+2天)%7例: 2000年3月1日星期几=(0+0/4+0+1+2)%7=3%7=星期三平4百年3月1日星期算法(百年%4<>0)其公式为:某年3月1日星期几=(百年%4*5天+年+年/4+月星期表+日+2天)%7 例:2100年3月1日星期几=(21%4*5+0/4*5+0%4+3)%7=(5+0+0+3)%7=8%7=星期一(注意:2100年是平年)其中万年某日星期算法 其公式为:某日星期几=(百年%4*5天+年+年/4+月星期表+日+2天)%73.2函数功能说明3.2.1总函数流程图 图3-1总函数流程图3.2.2参数说明(1)int isleapYear(int year);该函数判断某年是否是闰年,参数year表示要判断的年份,返回值1表示该年为闰年,0表示该年为平年。int IsLeapYear( int year )if (year %4 = 0) && (year % 100 != 0) |(year % 400 = 0) )return 1;elsereturn 0;开始流程图:Year%400 Return 1 Y NYear%100Return 0Year%4 Y N N YReturn 1Return 0 图3-2闰年判断(2)struct tm* getDay();该函数用以取得系统的时间。该函数没有参数,返回值类型为struct tm*,是一个包含时间的结构体struct tm* getDay()/从系统取得当前时间time_t timer;struct tm* gmt;time(&timer);gmt=localtime(&timer);return gmt;(3)int getwDay(int year,int month,int day);该函数用以根据一个日期推断星期,参数为要判断的年月日。返回值为整型,123456分别表示星期一到星期六,0表示星期天。int getwDay(int year,int month,int day)/取得星期int nday=0,nDay,i,w;for(i=0;i<month-1;i+)nday+=daysOfMonthrunYear(year)i;nday+=day;nDay=year-1+(year-1)/4-(year-1)/100+(year-1)/400+nday;w=nDay%7;return w;第四章 软件使用说明1、进入程序后显示 图4-1程序显示2、按任意字符键返回主菜单 图4-2主菜单3、进入主菜单后按1,显示当前时间 图4-3日历显示、4、在主菜单界面按2,进行日历的查询并经行日期的合法性判断和闰年的判断。图4-4输入合法 图4-5日历查询 图4-6输入不合法 图4-7修改日期此情况下,当输入正确的日期后,就可以显示月历,然后可以返回主菜单。5、在主菜单输入3,进入日期调整界面,可以通过方向键以及PageUp和PageDown进行日期的调整按向上键后出现如下结果 图4-8日期调整6、在主菜单中输入4,进入帮助界面图4-9帮助菜单7、在主界面中输入5,程序退出 图4-10程序退出 第五章 课程设计心得与体会通过课程设计,一方面是为了检查我们一个学期来我们学习的成果,另一方面也是为了让我们进一步的掌握和运用它,同时也让我们认清自己的不足之处和薄弱环节,加以弥补和加强。通过对万年历的设计进一步的巩固了用c语言和C+编写程序,并且有利于更好的掌握程序设计语言! 此程序是自己所写的第一个功能比较完整的能实现一定的实际功能的程序,代码比较短,不到250行,实现的功能有显示当前日历,进行某天的查询,闰年的判断,日期的合法性判断,日期的调整。然后在程序编写过程中,遇到了一些细节性的问题,比如在乱输入的情况下,有时会出现程序崩溃,后来通过修改,修正了漏洞。到写报告为止,漏洞基本被找出,并得到修正。通过写这个程序,我对程序的健壮性有了更深的认识,也更加注意程序的细节问题。在万年历的编写过程中也体会到了做事情一定要细心、认真。更加知道了要掌握好基础知识。还有体会到了成功的感觉。通过本项课程设计也培养了我独立思考、综合运用所学有关知识的能力,掌握工程软件的基本方法,强化上机动手变成能力,闯过理论与实践相结合的难关!在课程设计的过程中也知道了自己在以前的学习中有很大的不足导致在设计过程中出现了很多的问题,有些地方看不懂也不知道怎么去设计,但是在设计过程中也学习了很多,掌握了自己以前没有学好的知识,虽然一时可以掌握完以前没有学好的知识,不过也给自己敲响了警钟,在学习中不可以伏于表面,要想学好每一门课程都要踏踏实实,做什么都不是给别人看的!都是要更好的掌握该门知识,提高自己的自身的修养,提高自己的能力!为以后的工作打下良好的知识基础和技能基础!附录1 参考文献1谭浩强, 张基温. C语言程序设计教程. 北京: 高等教育出版社, 20002吴伟民. 数据结构课程设计. 北京: 清华大学出版社.2010孙宝山. Visual 3c#.NET应用程序设计. 北京:中国铁道出版社. 20084谭洪强. C+程序设计. 北京: 清华大学出版社. 20095李兰友,潘旭华,王占刚,孙宝山等编著.Visual c#.net应用程序设计.北京. 中国铁道出版社. 2008附录2 源程序#include<stdio.h>#include<time.h>#include<math.h>#include<windows.h>#include<conio.h> #define KEYNUMUp 0x48#define KEYNUMDown 0x50 #define KEYNUMLeft 0x4b #define KEYNUMRight 0x4d#define KEYNUMPageUp 0x49 #define KEYNUMPageDown 0x51 int year,month,day;/全局变量记录时间int daysOfMonth212=31,28,31,30,31,30,31,31,30,31,30,31,31,29,31,30,31,30,31,31,30,31, 30,31;int runYear(int year)/判断是否是闰年int flag=0;if(year%400=0|(year%4=0&&year%100!=0)flag=1;return flag;struct tm* getDay()/从系统取得当前时间time_t timer;struct tm* gmt;time(&timer);gmt=localtime(&timer);return gmt;int dayExame(int year,int month,int day)/检查日期是否正确if(year<0|month<1|month>12|day<1|day>31)return 0;switch(month)case 1:case 3:case 5:case 7:case 8:case 10:case 12:if(day>31)return 0;break;case 4:case 6:case 9:case 11:if(day>30)return 0;break;default:if(runYear(year)&&day>29)return 0;else if(runYear(year)=0&&day>28)return 0;return 1;int getwDay(int year,int month,int day)/取得星期int nday=0,nDay,i,w;for(i=0;i<month-1;i+)nday+=daysOfMonthrunYear(year)i;nday+=day;nDay=year-1+(year-1)/4-(year-1)/100+(year-1)/400+nday;w=nDay%7;return w;void printCalender(int year,int month,int day);void setDay(int &year,int &month,int &day)/调节日期printf("%c:上一年 %c:下一年n",24,25);printf("%c:上个月 %c:下个月n",27,26);printf("PageUp:昨天 PageDown:明天n");printf("其他:返回主菜单n");char k;getch();k=getch();switch(k)/通过方向键和PageUp、PageDown键来调整日期case KEYNUMUp:year-;if(dayExame(year,month,day)=0)year+; printf("%c",7);/检查日期的合法性,/若错误,保持日期不变,并警告system("cls");printCalender(year,month,day);setDay(year,month,day);break;case KEYNUMDown:year+;if(dayExame(year,month,day)=0)year-;printf("%c",7);system("cls");printCalender(year,month,day);setDay(year,month,day);break;case KEYNUMLeft:month-;if(dayExame(year,month,day)=0)month+;printf("%c",7);system("cls");printCalender(year,month,day);setDay(year,month,day);break;case KEYNUMRight:month+;if(dayExame(year,month,day)=0)month-;printf("%c",7);system("cls");printCalender(year,month,day);setDay(year,month,day);break;case KEYNUMPageUp:day-;if(dayExame(year,month,day)=0)day+;printf("%c",7);system("cls");printCalender(year,month,day);setDay(year,month,day);break;case KEYNUMPageDown:day+;if(dayExame(year,month,day)=0)day-;printf("%c",7);system("cls");printCalender(year,month,day);setDay(year,month,day);break;default:;void printCalender(int year,int month,int day)/打印月历int i;char wday74="Sun","Mon","Tue","Wed","Thu","Fri","Sat"printf(" %d年%d月%d日n",year,month,day);printf("*n");for(i=0;i<7;i+)printf("%5s",wdayi);printf("n");int w;int nowDay=1;w=getwDay(year,month,nowDay);/找到第一天的星期int n;n=daysOfMonthrunYear(year)month-1;switch(w)/放置第一天case 0:printf("%5d",nowDay);break;case 1:printf("%10d",nowDay);break;case 2:printf("%15d",nowDay);break;case 3:printf("%20d",nowDay);break;case 4:printf("%25d",nowDay);break;case 5:printf("%30d",nowDay);break;default:printf("%35dn",nowDay);nowDay+;for(i=1;i<n;i+)w=getwDay(year,month,nowDay);printf("%5d",nowDay);if(w=6)/如果是星期六则换行打印puts("n");nowDay+;printf("n*nn");void checkCalender()/查询日历system("cls");int year,month,day;printf("请输入你要查询的日期(格式为年月日,如2009 11 3):");scanf("%d%d%d",&year,&month,&day);while(!dayExame(year,month,day)/如果日期输入不正确,则重新输入printf("%c你输入的日期错误,请重新输入:",7);scanf("%d%d%d",&year,&month,&day);system("cls");if(runYear(year)printf("n闰年nn");else printf("n 平年nn");printCalender(year,month,day);void inline backMenu()printf("请按任意字符键返回主菜单:");getch();system("cls");void mainMenu(int &year,int &month,int &day)/主菜单printf("*主菜单*n");printf("*1、日历显示 *n");printf("*2、日历查询 *n");printf("*3、修改日期 *n");printf("*4、帮助 *n");printf("*5、退出 *n");printf("*n");char menu100;int flag=0;doint f=0;dof=0;printf("n请输入相应数字:");scanf("%s",menu);if(strlen(menu)>2)f=1;while(f=1);switch(*menu)case '1':system("cls");/清屏printCalender(year,month,day);backMenu();/实现任意键返回主菜单mainMenu(year,month,day);break;case '2':system("cls");checkCalender();backMenu();mainMenu(year,month,day);break;case '3':system("cls");printCalender(year,month,day);setDay(year,month,day);printf("请按任意字符键返回主菜单:");getch();system("cls");mainMenu(year,month,day);break;case '4':system("cls");printf("在主菜单中输入相应的数字就可以完成以下功能:nn");printf("* 1、显示今天所在月的月份nn");printf("* 2、输入日期,判断该年是否是闰年,并显示所在月份的月历nn");printf("* 3、用%c %c %c %c PageUp PageDown 进行日期的调整nn",24,25,27,26);printf("* 4、显示功能及操作方法nn");printf("* 5、退出程序nn");backMenu();mainMenu(year,month,day);break;case '5':system("cls");printf("程序已退出!n");exit(0);default:printf("%c输入错误!n",7);flag=1;while(flag);void main()struct tm *gmt=getDay();year=gmt->tm_year+1900;month=gmt->tm_mon+1;day=gmt->tm_mday;printCalender(year,month,day);/用系统时间进行初始化,打印当前月历backMenu();mainMenu(year,month,day);-