资源描述
.
C语言课程设计报告
题 目: 万年历
46 / 46
一 功能描述
万年历能实现一些功能,主要包括以下的几点.
(1) 日历显示功能.该日历能根据系统日期进行初始化,如果没有任何的输入,则会显示系统日期所在月份的日历,并能突出显示当前日期.
(2) 日期查询﹑闰年判断功能。输入日期进行查询,查询后将显示查询日期所在月份的月日,并突出显示查询日期。此外,还将显示查询日期所在年份是否是闰年。
(3) 支持键盘操作。支持键盘操作,可以通过键盘操作调整年份﹑月份和日期,并显示调整后的日期。还可以通过键盘操作复位到系统所在日期等。
(4) 参数检查功能。程序还设置有参数检查功能,即对输出的日期进行合法性检查。如果年份﹑月份或者田鼠不合法,查询将被拒绝,并显示提示信息。
二 总体设计
1.功能模块图
本系统包括4个模块,分别是功能控制模块﹑打印输出模块﹑日历显示模块和键值获取模块,如图12.1所示。
功能控制模块
打印输出模块
日历显示模块
键值获取模块
万年历系统
图12.1 系统模块图
1. 功能控制模块。该模块用于实现日期有效性检查﹑判断是否是闰年和返回指定日期对应的日期。
2. 打印输出模块。该模块主要是进行输出显示,包括打印指定个数的空格﹑打印分隔线﹑打印用户使用手册﹑打印当前日期对应的星期以与打印指定的星期。
3. 日历显示模块。该模块是系统的核心模块,是用来显示指定日期所在月份的月历。
4. 键值获取模块。该模块接受键盘操作,获取键值,来进行日期调整,并调用日历显示模块中的函数来显示调整后的日历。
2 日历显示流程图
历显示是系统的核心模块,它控制着日历的生成和显示。其实现流程如图12.2所示。程序输入的是包含年月日的日期,输出month所在月份的月历,并突出显示day所在的日期和year是否是闰年的标识。程序首先根据判断year其是否是闰年,如果是则需要将该年2月份的天数设置为29天,接着判断day是否超过month所在的月份的最大天数,如果超过则显示系统日期所在的月历。然后进行星期输出的判断,如果输出的是该月的第一个星期,则判断该星期中还有几天在本月(如,该月1号是星期五,则表示该月第一个星期中只有两天在本月,星期一到星期四在上月,则星期一到星期四在本月就不输出,仅有空格表示),输出完第一周后,接着输出第二到第五(或者六)周,每周7天。在输出过程中,如果遇到了day所在的日期,则突出显示。
3.键值获取流程图
键值获取实现的是从键盘调整日期并显示调整后的日历。系统首先 判断从键盘输入的 值,如果是右移键,表示增加月份。如果 左移键,表示减少月份。如果上移键,表示增加年份。如果下移键表示减少年份。如果上翻页键表示减少日期。如果是下翻页键表示增加日期。如果Q/q键表示查询日期,此时将输出提示信息,提示用户输入查询日期。在用户输入查询日期后,系统将调用日期检查函数对输入日期的 合法性进行检测,如果输入日期不合格,则提示错误信息并显示当前系统日期所在月的 月历;如果是 空格键表示重置,显示当前系统日期所在月的 月历;如果是Esc键表示退出系统,按此键后,系统将询问用户是否确定退出,在得到确定回答(用户输入Y/y)后将退出系统。
三 数据结构设计
本程序没有自定义结构体,在此仅讲述定义的全局变量。
Struct data sysTime:系统结构体,用于存储系统日期。该结构体有3个成员,分别是da_year、da_mon和da_day,表示年、月和日。
Int currentYear:表示当前年份。
Int currentMonth:表示当前月份。
Int currentDay:表示当前日期。
Int n_currentMon:表示当前月的天数。
Int n_lastMon:表示上一个月的 天数。
12.3.3函数功能描述
1)checkDate()
函数原型:void checkDate()
checkDate()函数用于检查输入日期的合法性,包括检查输入日期中的年、月、日部分。对于年,检查其是否是负数或者是0;对于月,检查其是否是围1~12中的值;对于日,检查其是否是围1~31中的值。如果有一个部分不合法,则程序提示用户。
2)isLeapyear()
函数原型:isLeapyear()
isLeapyear()函数用于判断指定年份是否是闰年。参数year为待判断的年份。
3)getWeek()
函数原型:int getWeek(int year,int month,int day)
getWeek()函数用于计算并返回给定日期对应的星期。其中参数year、month和day都为整型,分别表示输入的年、月、日。
4)printSpace()
函数原型:void printSpace(int n)
printSpace()函数用于输出指定个数的空格。其中整型参数n表示需要输出的空格的个数。
5)printSeparator()
函数原型:void printSpace()
printSpace()函数用于输出分隔线。将输出的界面美化,使得界面结构分明。分隔线用若干个“=”表示。
6)printUsage()
函数原型:void printSpace()
printSpace()函数用于在指定位置输出用户使用手册。输出位置在函数中已经设定。
7)printWeek()
函数原型:void printWeek()
printWeek()函数用于输出当前日期对应的星期,即由currentYear、currentMonth和currentDay确定的日期对应的星期。该函数首先调用printWeek()函数返回当前日期对应的星期。
8)printWeek2()
函数原型:void printWeek2(int week)
printWeek2()函数用于根据指定值输出星期。参数week是一个整型变量,其值可取0到6,分别表示星期一到星期日。
9)showCalendar()
函数原型:void showCalendar(int year,int month,int day)
showCalendar()函数用于显示日历。参数year、month和day分别表示年、月和日。该函数显示year所在年是否是闰年,显示month所在的月历,突出显示day所在日的日期。
10)getKeyValue()
函数原型:void getKeyValue()
getKeyValue()函数用于获取键盘的输入。根据键盘的输入(上下移键、左右移键、上下翻页键Q/q键)调整当前日期,并显示当前所在月的月历等。
四 程序实现
源码分析
1. 程序预处理
程序预处理包括头文件的加载、常量×的定义和全局变量的定义.
/*加载头文件*/
#include<stdio.h>
#include<bios.h>
#include<dos.h>
#include<conio.h>
/*定义常量*/
/*左移键*/
#define LEFT 0×4b00
/*右移键*/
#define RIGHT 0×4d00
/*下移键*/
#define DOWN 0×5000
……
/*Esc键*/
#define ESC 0×011b
/*定义全局变量*/
Struct data systime;
int currentyear;
……
/*﹉﹉﹉﹉﹉自定义函数﹉﹉﹉﹉﹉﹉*/
Void checkDate();
int isLeapyear(int year);
……
Void getKeyValue();
2.功能控制模块
功能控制模块包括日期合法性的检查功能、闰年判断功能和星期计能,分别由函数checkDate()、isLeapyear()和etWeek()实现。
(1) void checkDate(),检查日期合法性。
Void checkDate()
{/*如果给定的日期中年份部分为负数或者0*/
If( rrentYear<=0)
gotoxy(1,27);
printf(“The year should be a positive number !\n);
gotoxy(1,28)l
printf(“Press any key to continue……”);
getchar();
getchar();
/*以当前系统时间重新赋值*/
currentYear=sysTime.da_year;
currentMonth=sysTime.da_mon;
currentDay=sysTime.da_day;
}
/*如果给定的日期中月份部分为负数,为0或者大于12*/
/*如果给定的日期中天数部分为负数,为0或者大于31*/
(2) int isLeapyear(int year),判断指定年是否是闰年。
/*闰年的判断(1)year被4整除,并且yea不被100整除或(2) year被4整除,并且year被400整除*/
int isLeapyear(int year )
{ if(year%4==0&&year%100︱︱year%400==0)
return 1;
else return 0;
(3) int getWeek(int year,int month,int day),据给定年月日计算其对应的星期。
int getWeek(int year,int month,int day)
{
int leapFlag;
int week;
int i;
/*该数组用于保存每个月的天数*/
/*判断给定年份是否是闰年*/
if(leapflag==0)
/*计算从给定年份的1月1日到给定日期之间的天数*/
/*计算日期*/
3.打印输出模块
打印输出模块包括打印指定个数空格、打印用户使用手册和打印星期功能等,分别由函数printSpace()、printSeparator()、printUsage()、printWeek()、printWeek2()实现。
(1) void printSpace(int n),打印n个空格.
(2) void printSeparator(),打印分隔线.
(3) void printUsage()打印用户使用手册.
(4) void printWeek(),根据当前日期计算对应星期,并打印输出.
(5) void prinWWk2(int week),打印由week指定的星期。
/*输出指定个数个空格函数*/
void printSpace(int n )
{ int i;
for(i=0;i〈n;i++〉
printf(“”);
}
/*输出分隔线函数*/
void printSeparator()
{ int i ;
for(i=0;i〈38;i++〉
{printf(“=”);}
printf(“\n”);
}
/*输出使用方法函数*/
void printfUsage()
{ gotoxy(45,3);
/*设定字体颜色*/
textcolor(YELLOW);
/*送格式化输出至屏幕*/
cprintf(“-------------Usage--------------------”);
gotoxy(45,3);
textcollor(YELLOW);
cprintf(“YEAR”);
gotoxy (50,5);
printf(“Up key ()to increase”);
gotoxy(50,7;)
printf(“Down key () to decrease”);
gotoxy(45,13);
textcolor(YELLOW);
cprintf(“Day”);
gotoxy(50,13;)
printf(“PageDown key to increase;”);
gotoxy(50,15);
printf(“PageUp key to decrease”);
gotoxy(45,17);
Extcollor(YELLOW);
cprintf(“QUERY”);
gotoxy(50,17;)
printf(“Q/q key\n”);
textcollor(YELLOW);
gotoxy(45,19);
cprintf(“RESET”);
gotoxy(50,19);
printf(“SPACE key .\n”);
gotoxy(45,21);
textcollor(YELLOW);
cprintf (“EXIT”);
gotoxy(50,21);
printf(“Esc key\n”);
gotoxy(59,5);
/*设置寄存器,表示在指定位置输出一次指定的字符*/
-Cx=01;
-AR=0x8;
/*指定输出字符为向上的箭头*/
-AL=24;
/*产生一次中断,输出向上箭头*/
geninterrupt(0x10);
gotoxy(61,7);
-cx=01;
-AX=0xa;
/*指定输出字符为向下箭头*/
-AL=25;
geninterrupt(0x10);
……
/*根据系统日期输出星期函数*/
void printWeek()
{
int day;
/*根据系统日期获得星期*/
day=getweek()
textcolor(11);
/*输出星期。0表示星期天,1表示星期一*…/
if(day==0)
cprintf(“%d-%d-%d,Sunday!”currentYear,currentMonth,currentDay);
if(day==1)
cprintf(“%d-%d-%d,Monday!”currentYear,currentMonth,currentDay);
if(day==2)
cprintf(“%d-%d-%d,Tuesday!”currentYear,currentMonth,currentDay);
if(day==3)
cprintf(“%d-%d-%d,Wednesday!”currentYear,currentMonth,currentDay);
if(day==4)
cprintf(“%d-%d-%d,Thursday!”currentYear,currentMonth,currentDay);
if(day==5)
cprintf(“%d-%d-%d,Friday!”currentYear,currentMonth,currentDay);
if(day==6)
cprintf(“%d-%d-%d,Saturday!”currentYear,currentMonth,currentDay);
textcollor(7);
/*输出指定的星期函数*/
Void printWeek2(int week)
{
If(week==0)
Cprintf(“,Sunday”);
If(week==1)
Cprintf(“,Monday”);
If(week==2)
Cprintf(“,Tuesday”);
If(week==3)
Cprintf(“,wednesday”);
If(week==4)
Cprintf(“,Thursday”);
If(week==5)
Cprintf(“,Friday”);
If(week==6)
Cprintf(“,Surtaday”);
}
4.日历显示模块
日历显示模块是本程序的核心模块,该模块实现了日历的生成和显示功能。该模块由函数实现,其程序流程可参见图。
/*显示日历函数*/
Void showCalendar(int year,int month ,int day)
{int i;
Int j;
/*输出的日期*/
Int outDay ;
Int leapFlag;
/*本月第一个星期中,在上月的天数*/
Int dayLastMon;
Int week;
/*该数组用于保存每个月的天数*/
Int a[13]={0,31,28,31,30,31,30,31,30,31,30,31,30,31}
Out/day=0
dayLast=0;
wek=0;
/*判断给定年份的日期中,天数大于该月的最大天数*/
leapFlag=isLeapyear(year);
/*如果是闰年则2月应该是29天*/
if(;eapFlag==1)
{a[2]++;
}
/*如果给定的日期中,天数大于该月的最大天数*/
If(day>a[month])
{
Printf(“The number of this month’s day is %d atmost!\n”,a[month]);
Getchar();
Gerchar();
/*以当前系统时间重新赋植*/
year=systime.da_year;
month=systime.da_mon;
day=systime.da.day;
currentyear= systime.da_year;
currentmonth= systime.da_mon;
currentday= systime.da.day;
}
/*当前月的天数*/
n_currentmon=a[month];
/*上一月的天数*/
n_lastmon=a[month-1];
/*根据给定的日期,获取给定月份1号的星期*/
week=daylastmon=getweek(year,month,1);
/*输出月份提示,1-12分别表示1月到12月*/
Switch (month)
{
case1:
cprintf(“January 1”);
Break;
Case2:
cprintf(“February 2”);
Break;
Case3:
cprintf(“march 3”);
Break;
Case4:
cprintf(“April 4”);
Break;
Case5:
cprintf(“May 5”);
Break;
Case6:
cprintf(“June 6”);
Break;
Case7:
cprintf(“July 7);
Break;
Case8:
cprintf(“August 8”);
Break;
Case9:
cprintf(“September 9”);
Break;
Case10:
cprintf(“October 10”);
Break;
case11:
cprintf(“November 11”);
Break;
case12:
cprintf(“December 12”);
Break;
}
Textcolor(7);
printf(“\n\n”);
textcolor(13)
Printf(“Sun,Mon,……\n\n”);
Textcolor(7)
Printf(“\n\n”);
/*因为一 个月中最多跨度6个星期,所以循环从0到5*/
For(i=0;i<6;i++)
{
/*如果是该月的第一个星期*/
if(i==0)
{
/*第一个星期中还要7天本月,有7天在上个月,所以输出dayleatMon*4个空格,每个空格在日历中占用4 个空格*/
printSpace(dayLastMon*4);
/*剩余在本月的第一个星期中的天数为*/
for(j=0;j<7_dayLastmon;j++)
{
/*到达前一天时,输出*/
If(outDay==day_1)
/*用黄色字体突出显示*/
textcollor(YELLOW);
cprintf(“[%d]”,++outDay);
textcollor(7);
}
/*到达当天时,并且不是星期天*/
else if(outday==&&week!=0)
{
printf(“%3d.++outday”);
}
/*到达当天时。并且是星期天*/
else{ printf(“%3d.++outday”); }
/*计算当天的星期,如果前一 天是星期六,则当天是星期天,其他的情况则直接星期加1*/
week=(week<6)?week+1:0;
}
printf(“\n\n”);
}
/*如果不是该月的第一个星期*/
else {
/*输出的天数小于该月的最大天数*/
for(j=0;j<7;j++)
{
/*到达当天的前一天时,输出*/
if(outday==day_1)
/*输出一 位数字*/
if(outsay<9)
{ textcollor(YELLOW);
cprintf(“[%d]”,++outDay);
textcollor(7);
}
/*输出两位数字*/
else { textcollor(YELLOW); }
cprintf(“[%d]”,++outDay);
textcollor(7);
}
}
else if(outday==&&week!=0)
{
printf(“%3d.++outday”);
}
/*到达当天时,并且不是星期天*/
else{ printf(“%3d.++outday”); }
/*计算当天星期*/
week=(week<6)?week+1:0;
}
printf(“\n\n”);
if(outDay==a[month])break;
}
}
/*输出分隔线*/
printSepartor();
(接下为输出)
5.键植获取模块
键植获取模块主要用于对键盘操作的响应,获取按键植,根据键植调整当前日期,并调用日历显示模块中的函数实现日历的生成 和输出。该模块由函数来实现,其流程可参见图
/*通过键盘调整日期函数*/
void getKeyValue()
{int key;
char ch;
/*默认显示当前系统日期和星期*/
currenYear=systime.da_year;
currenMon=systime.da_mon;
currenDay =systime.da_day;
}
showCalendar(currenYear, currenMon, currenDay);
while(1)
{
/*获取键值,根据键值调整日历输出*/
key=bioskey(0);
/*右移键,增加月份*/
if(key==RIGHT)
{
if(currenMon<12&& currenMon>=1)
{ currenMon++;
}
/*如果月份为12则加1后进位,即年份加1.月份变为1*/
else{ currenYear++ ; currenMonth=1; }
}0
/*左移键,减少月份*/
if(key==LEFT)
{ if(currenMon<=12&& currenMon>1)
{ currenMon++;
}
/*如果月份为1,则减1后,到上一年,月份变为123*/
else{ currenYear-- ; currenMonth=12; }
}
/*上移键,增加年份*/
if(key==UP)
{ currenYear++ ;}
/*下移键,减少年份*/
if(key==DOWN)
{ currenYear-- ;}
/*上移键,减少天数*/
if(key==PAGEUP)
{ /*当前日不是该月的第一天,则天数直接减1*/
if(currenDay!=1)
{ currenDay--; }
/*当前日是该月的第一天,并且是该年的第一个月,则天数减1后,变为上一年的最后一个月的一个月的最后一天*/
else if(currenDay==1&& currenMon==1)
{ currenYear++ ;
currenMon=12;
currenDay=31;
}
/*当前日是该年中某个月的最后一天,则天数减1后,变为上个月的最后一天*/
else {currenMon--; currenDay =n_lasrMon; }
/*下键,增加天数*/
if(key==PAGEDOWN)
{
/*当前日不是该月的最后的一天,则天数直接加1*/
if(n_ currenMon!= currenDay)
{ currenDay++; }
/*当前日是该年中耨I 月的最后一天*,则天数就加1后,变为下一个年的第一个月的第一天/
else if(n_ currenMon== currenDay&& currenMon==12)
{ currenYear++ ;
currenMonth =1;
currenDay=1; }
else
{ currenYear++ ;
currenDay=1;
}
}
/*Q或者q键,表示查询指定日期的星期*/
if(key==QLOWER︱︱key==QUPPER)
{
{ printf(“Input date(eg,%d-%d-%d):”, systime.da.day; systime.da_mon ,systime.da_year)
scanf(“%d-%d-%d)”,¤Year,¤Month,¤Day );
checkDate();
}
}
/*空格键,重置到系统日期*/
if(key==SPACE)
{
currenYear=systime.da_year;
currenMon=systime.da_mon;
currenDay =systime.da_day;
}
/*Esc键退出系统*/
if(key==ESC)
{
printf(“Do you really want to quit?(Y/N)”);
ch=getchar();
if(ch==‘y’ ︱︱ch==‘Y’)
break;
}
showCalendar(currenYear, currenMon, currenDay);
}
}
6.主函数
本程序的主函数实现比较简单,主函数首先控制寄存器来设置屏幕显示方式,然后通过系统函数获取系统日期,作为日历显示的初始化日期,然后调用getKeyValue()函数来进行按键控制操作。
/*主函数*/
void main()
{
/*清除文本模式窗口*/
clrscr();
/*设置屏幕显示方式*/
_AL=03;
_AH=0;
geninterrupt(0x10)
getdate(&systime);
getKeyValue();
}
五 运行结果
本节将描述程序的运行结果,包括程序的开始和退出操作、各种按键操作以与日期合法性的检测结果等。
1. 程序开始与退出
程序以系统的日期进行初始化,程序开始时显示的是系统日期所在月的月历,如图12.4所示。图中第一行显示了该年是否是闰年(绿色字迹突出显示),图的右边部分显示的是用户使用手册,图的左边部分显示了该月的月历,包括日期和其对应的星期,并突出显示了当前日期(该程序是2007年6月17日星期日运行的)。
The calendar of 2007 [not leap year]
=====================================
June 6 ------------------------Usage----------------------
Sun Mon Tue Wed Thu Fri Sat YEAR Up key(↑) to increase ;
1 2 Down key(↓) to decrease .
3 4 5 6 7 8 9 MONTH Right key(→) to increase ;
10 11 12 13 14 15 16 Left key(←) to decrease .
17 18 19 20 21 22 23 DAY PayeDown key to increase ;
24 25 26 27 28 29 30 PageUp key to decrease .
===================================== QUERY Q/q key
The day you choose is: RESET SPACE key .
2007-6-17, Sunday! EXIT Esc key
------------------------------------
Today is: 2007-6-17, Sunday
图12.4 程序开始
要想退出程序,可按Esc键。程序将询问用户是否确定退出,如图12.5所示。如果要确定退出可输入“Y”或者“y”,按Enter键即可。这里,由于我们还要继续操作,所以不退出程序,而输入“n”表示不退出程序。
The calendar of 2007 [not leap year]
=====================================
June 6 ------------------------Usage----------------------
Sun Mon Tue Wed Thu Fri Sat YEAR Up key(↑) to increase ;
1 2 Down key(↓) to decrease .
3 4 5 6 7 8 9 MONTH Right key(→) to increase ;
10 11 12 13 14 15 16 Left key(←) to decrease .
17 18 19 20 21 22 23 DAY PayeDown key to increase ;
24 25 26 27 28 29 30 PageUp key to decrease .
===================================== QUERY Q/q key
The day you choose is: RESET SPACE key .
2007-6-17, Sunday! EXIT Esc key
------------------------------------
Today is: 2007-6-17, Sunday
Do you really want to quit ?(Y/N)n
图 12.5 退出程序
2. 移动上下键
移动上下键可以调整日期中表示年的部分。控制向上键可以增加年份,如图12.6所示。系统日期是2007年6月17日,星期一,按向上键后,程序将显示2008年6月的月历。通过图中第一行可以得知,2008年是闰年。此外,在图中左下部分的“The day you choose is:” 下的日期变为“2008-6-17,Tuesday”,这表示当前选择的日期是2008年6月17日,星期二。
The calendar of 2008 [ leap year]
=====================================
June 6 ------------------------Usage----------------------
Sun Mon Tue Wed Thu Fri Sat YEAR Up key(↑) to increase ;
1 2 3 4 5 6 7 Down key(↓) to decrease .
8 9 10 11 12 13 14 MONTH Right key(→) to increase ;
15 16 17 18 19 20 21 Left key(←) to decrease .
22 23 24 25 26 27 28 DAY PayeDown key
展开阅读全文