万年历课程设计.docx
- 文档编号:25597727
- 上传时间:2023-06-10
- 格式:DOCX
- 页数:48
- 大小:338.88KB
万年历课程设计.docx
《万年历课程设计.docx》由会员分享,可在线阅读,更多相关《万年历课程设计.docx(48页珍藏版)》请在冰豆网上搜索。
万年历课程设计
C语言
课程设计报告
设计题目:
万年历
学生姓名:
学生学号:
专业班级:
学院名称:
同组人姓名:
指导老师:
2011年6月15日
3详细设计…………………………………………………………………………………………9
4测试结果与分析………………………………………………………………………………..15
附录………………………………………………………………………………………………..21
1需求分析
1.1问题描述
我们将该课题分解为万年历和备忘录两部分,两人各完成其中的一部分。
我们定义了一个structdate_message型结构体变量date用来存放年月日以及对应的备忘。
由于课题要求使用命令行参数来实现各种功能,因此我们参考了一系列C语言教材,自学了命令行参数的使用,并使用getopt函数来实现参数的分析,最后根据getopt函数返回的值用switch语句选择程序的功能。
(允许在输入参数时只有年份月份没有日期)
1.关于万年历,我们先计算当月第一天是星期几,再依次将接下来的日期排下来。
针对当月第一天星期的求解,我们以2011年1月1日为基点(星期六),计算所求日期与该日相差的天数取余(讨论年份在2011两边的两种情况),之后通过一定的输出手段将日历输出。
2.关于备忘,我们除了实现要求中的显示功能和添加功能外,增加了程序的三项功能:
修改功能、删除单日备忘功能、删除所有备忘功能。
提供多备忘的添加功能。
通过文件的写入与读取(删除功能使用了空结构体变量覆盖的办法),实现以上的各项功能。
1.2输入数据要求
由于使用了命令行参数,所以该程序的运行必须在DOS环境下。
在“命令行提示符”中按“可执行文件的路径空格负号命令选项空格命令选项所带的参数”的顺序输入。
我们将该文件命名为calender.exe,参数为年月日(允许在输入参数时只有年份月份没有日期,使用选项-t时不允许输入年月日)。
各命令选项的功能如下:
/*-d:
显示当月日历和当日备忘*/
/*-i:
显示当月日历和添加当日备忘*/
/*-m:
显示当月日历和修改当日备忘*/
/*-g:
删除当日备忘*/
/*-t:
删除全部备忘*/
下面就各命令选项给出一部分样例:
C:
\Windows\system32>E:
\calendar–d2011615
C:
\Windows\system32>E:
\calendar–i688868
C:
\Windows\system32>E:
\calendar–m999999
C:
\Windows\system32>E:
\calendar–g1234567
C:
\Windows\system32>E:
\calendar–t
样例输入的截图如下:
1.3输出数据要求
根据输入参数信息,使用不同的功能。
注:
允许多备忘存在,但此处不作为样例截图。
针对样例输入的五种功能的输出如下:
1.显示当月日历和当日备忘:
基本功能,显示当月日历和当日备忘。
2.显示当月日历和添加当日备忘:
输入所需要添加的备忘,提示“添加成功后”之后显示添加后的当月日历和当日备忘。
3.显示当月日历和修改当日备忘:
与添加备忘的程序运行结果类似。
4.删除当日备忘。
提示确认信息,当输入y时删除。
如果该日本身无备忘的话,提示“该日无备忘!
”
5.删除全部备忘。
提示确认信息,当输入y时删除。
1.4开发环境和工具
开发环境:
Windows7
开发工具:
Dev-C++4.9.9.2
1.5成员分工
胡凡:
总体设计、主调模块、备忘录功能实现、注释编写
叶磊:
主调模块、万年历功能实现、数据测试、注释编写
2总体设计
2.1总体设计思路
1.设计思路
考虑到日期与备忘的一一对应,采用结构体来解决该题成为一个可行的思路。
首先,定义结构体类型,使得年月日与备忘直接绑定在一起。
通过程序中这一临时存放数据的变量,使用文件的读写功能向文件中写入文件以及读出信息以暂时使用。
针对日历的输出,首要考虑的是当月1日的输出位置,即需要求出该月1日是星期几。
针对这个问题,我们以2011年1月1日为基点,求所求日期与基点距离的天数之差,之后根据除以7取的余数来看星期。
选择2011年1月1日为基点,是因为其满足计算的两个条件:
1.该日正好为年首,使得计算相差天数的计算变得更为简单。
2.该日正好是星期六,使得相差的天数除以7所取出来的余数正好按日历从左至右显示(我们输出的日历从左往右依次为星期日、一、二、三、四、五、六)。
我们考虑2011年前与后的两种情况。
2011年后所需的即为正常余数,2011年前的则需要用7减去得到的余数才是所欲要的值。
之后经过一定的输出格式即可将日历输出。
针对备忘录的编写,考虑到定义了一个结构体使得年月日与备忘相连,因此可以将年月日与备忘一同存入文件。
考虑到万年备忘录的庞大,为了节省时间和空间,我们想出了一个算法:
在添加写入文件时,一律将数据内容写入文件末尾(即使用ab+追加模式);而当读取文件时,则将文件内的年月日与外部参数输入的年月日相比较,不相同则位置指针下移,一直到年月日相同或者无法读取为止。
这样编写可以避免考虑年份的上限大小(因为如果定义一个二维数组,虽然也可以将日期和备忘一一对应,但是这样的话处理这个数组的上限就不好操作了。
如果数组开太大会直接影响运行速度),而且在存入的备忘不太多的情况下在时间和空间上都可以节省(空间只跟存入的备忘数目有关,而不是直接开很大的数组,这样即使年份很大也不会对空间大小有什么影响)。
另外,我们设计了备忘修改功能、备忘删除(单日或全部),使得操作可以更人性化。
另外,多备忘录的添加、修改、删除(当天单条、当天所有、全部天的备忘)都是允许的。
最后,在自学了命令行参数之后,我们用argc和*argv[]将主函数写出,并且用getopt函数来处理接收的参数并返回命令选项。
之后便可以通过返回的命令选项用switch语句选择所需要实现的功能。
以上即为我们对该课题的总体设计思路。
2.数据存储
将年月日与对应的备忘放于同一结构体变量中,在使用文件读写时作为一个整体使用,也方便了添加功能、修改功能、删除功能的实现。
2.2模块结构图
根据需求将系统划分为四个功能模块,函数之间的调用关系如图2.1所示。
图2.1晚年备忘录的模块结构图
1)Main:
主函数。
2)leap:
闰年判断。
3)checkDate:
检查日期合法性
4)show_calender:
显示当日的日历(未输入日时显示当月1日的日历)。
5)memo_read:
备忘的读取。
6)memo_written:
备忘的写入。
7)memo_modify:
备忘的修改。
8)memo_delete:
备忘的删除(当日(其中分为单条删除和全部删除))。
9)memo_delete_all:
备忘的删除(全部)。
2.3模块说明
(以从上至下,从左至右的顺序说明)
1.MathPath模块
函数原型:
intmain(intargc,char*argv[])
功能:
主函数
输入参数:
argc——int类型,表示录入参数的个数
*argv[]——char类型,各元素记录各种录入字符串的首地址
输出参数:
0——int类型,返回给系统一个值,说明程序正常终止
2.leap模块
函数原型:
intleap(intt_year)
功能:
闰年判断
输入参数:
t_year——int类型,表示需要判断闰年的年份
输出参数:
1——int类型,如果是闰年则返回1;
0——int类型,如果是非闰年则返回0;
3.checkDate模块
函数原型:
voidcheckDate()
功能:
检查输入年月日的合法性
输入参数:
year——int类型,表示年份
month——int类型,表示月份
day——int类型,表示日期
输出参数:
无
4.show_calender模块
函数原型:
voidshow_calender()
功能:
显示日历
输入参数:
date.year——int类型,表示年份
date.month——int类型,表示月份
date.day——int类型,表示日期
输出参数:
无
5.memo_read模块
函数原型:
voidmemo_read()
功能:
从文件读取备忘
输入参数:
date.year——int类型,表示年份
date.month——int类型,表示月份
date.day——int类型,表示日期
输出参数:
无
6.memo_written模块
函数原型:
voidmemo_written()
功能:
将备忘写入文件
输入参数:
date.year——int类型,表示年份
date.month——int类型,表示月份
date.day——int类型,表示日期
输出参数:
无
7.memo_modify模块
函数原型:
voidmemo_modify()
功能:
修改备忘
输入参数:
date.year——int类型,表示年份
date.month——int类型,表示月份
date.day——int类型,表示日期
输出参数:
无
8.memo_delete模块
函数原型:
voidmemo_delete()
功能:
删除备忘(当日)
输入参数:
date.year——int类型,表示年份
date.month——int类型,表示月份
date.day——int类型,表示日期
输出参数:
无
9.memo_delete_all模块
函数原型:
voidmemo_delete_all()
功能:
删除备忘(全部)
输入参数:
无
输出参数:
无
3详细设计
3.1数据类型定义
1.结构体类型的定义及初始化
/*定义结构体*/
structdate_message
{
intyear;/*年*/
intmonth;/*月*/
intday;/*日*/
charmemo[300];/*备忘*/
}date={1,1,1,"\0"};
2定义全局变量
/*定义全局变量(各月所含天数)*/
inta[]={0,31,0,31,30,31,30,31,31,30,31,30,31};
3.2模块实现
由于各人分工,故以下贴出的是自己负责模块的实现(此部分为备忘录功能模块的实现)
MathPath模块实现
1.算法思想
首先进行函数调用声明。
定义一个变量choice,用来记录getopt函数分析完参数之后的返回值,即命令选项,之后使用switch语句对命令选项进行判断,根据不同的命令选项执行不同的功能。
2.具体实现
(关键代码)
intmain(intargc,char*argv[])
{
/*函数声明*/
voidcheckDate();/*检查日期合法性*/
voidshow_calender();/*显示日历*/
voidmemo_written();/*写入备忘*/
voidmemo_modify();/*修改备忘*/
voidmemo_delete();/*删除当日备忘*/
voidmemo_delete_all();/*删除全部备忘*/
voidmemo_read();/*读取备忘*/
/*定义变量*/
intchoice;
/*使用getopt函数分析命令行参数,识别选项*/
while((choice=getopt(argc,argv,"d:
i:
m:
g:
t"))!
=-1)
{/*选项*/
switch(choice)
{case'd':
/*调用函数,显示当月日历和当日备忘*/
case'i':
/*调用函数,显示当月日历和添加当日备忘*/
case'm':
/*调用函数,显示当月日历和修改当日备忘*/
case'g':
/*调用函数,删除当日备忘*/
case't':
/*调用函数,删除全部备忘*/
}
}
printf("\t\tPleaseanykeytocontinue…………");
getchar();
system("cls");
return0;
}
memo_read模块实现
1算法思想
依次读取文件的一个结构体长度的数据,直到读取的年月日与外部输入的年月日相等或者文件无法继续读取,再将最后读取的年月日输出。
2具体实现
(关键代码)
/*备忘读取*/
voidmemo_read()
{
/*定义文件指针*/
FILE*fp;
/*定义变量*/
inti;
structdate_messagetemp={0,0,0,"\0"};
/*总是在读取备忘之前令备忘数归零*/
count_memo=0;
/*打开文件*/
if((fp=fopen("calender.txt","ab+"))==NULL)
{
printf("\t\t\t\t打开文件失败\t\t\t\t\n");
return;
}
/*查找文件中是否有相同的日期*/
while
(1)
{
/*文件读到不能读取为止*/
if(fread(&temp,sizeof(structdate_message),1,fp)!
=1)break;
/*如果文件该位置的时间与所求时间相同*/
if((temp.year==date.year)&&(temp.month==date.month)&&(temp.day==date.day))
{
/*当天备忘个数的计数*/
count_memo++;
for(i=0;i<300;i++)
date.memo[i]=temp.memo[i];
printf("\n\t\t\t备忘%d:
%s\n",count_memo,date.memo);
}
}
/*如果没有相同日期的话*/
if(count_memo==0)
printf("\t\t\t\t该日暂无备忘\n\n");
printf("\n");
fclose(fp);
}
memo_written模块实现
1算法思想
使用文件的追加模式打开,每次将需要写入的数据写于文件最后。
2具体实现
(关键代码)
/*备忘写入*/
voidmemo_written()
{
/*定义文件指针*/
FILE*fp;
/*打开文件*/
if((fp=fopen("calender","ab+"))==NULL)
{
printf("\n\t\t\t\t打开文件失败\n\n\t\t\t");
return;
}
/*输入备忘*/
scanf("%s",date.memo);
/*写入备忘*/
if(fwrite(&date,sizeof(structdate_message),1,fp)==1)
{
system("cls");
printf("\n\t\t\t\t备忘存入成功\n\n\t\t\t");
}
else
{
system("cls");
printf("\n\t\t\t\t备忘存入失败\n\n\t\t\t");
}
getchar();
fclose(fp);
}
memo_modify模块实现
1算法思想
依次读取文件的一个结构体长度的数据,直到读取的年月日与外部输入的年月日相等或者文件无法继续读取,调整位置指针的位置使得指针指向需要修改的结构体,之后将需要修改的数据写入即可。
2具体实现
(关键代码)
/*备忘修改*/
voidmemo_modify()
{
/*定义文件指针*/
FILE*fp;
/*定义变量*/
inti=0,t,count=0;
structdate_messagetemp;
/*打开文件*/
if((fp=fopen("calender.txt","rb+"))==NULL)
{
printf("\n\n\n\n\n\n\n\n\n\t\t\t打开文件失败\n\n");
return;
}
printf("请输入要修改第几条备忘\n");
/*输入需要修改第几条备忘*/
scanf("%d",&t);
if(!
(t>0&&t<=count_memo))
{
printf("输入错误!
该次操作失败\n!
");
getch();
system("cls");
exit(0);
}
printf("请输入要修改的内容\n");
/*输入备忘*/
scanf("%s",&date.memo);
/*在文件中寻找该日期*/
while
(1)
{
/*移动指针位置*/
fseek(fp,i*sizeof(structdate_message),0);
/*到文件无法读取时退出*/
if(fread(&temp,sizeof(structdate_message),1,fp)!
=1)break;
/*如果文件中的时间与所求时间相同*/
if((temp.year==date.year)&&(temp.month==date.month)&&(temp.day==date.day))
{
/*备忘计数+1*/
count++;
/*对应上同一个备忘的时候*/
if(count==t)
{
fseek(fp,i*sizeof(structdate_message),0);
/*覆盖*/
fwrite(&date,sizeof(structdate_message),1,fp);
break;
}
}
i++;
}
printf("\n\t\t\t\t修改成功!
\n\n");
getch();
system("cls");
fclose(fp);
}
memo_delete模块实现
1算法思想
依次读取文件的一个结构体长度的数据,直到读取的年月日与外部输入的年月日相等或者文件无法继续读取,调整位置指针的位置使得指针指向需要删除的结构体,之后将空结构体写入即可。
2具体实现
(关键代码)
/*当日备忘删除*/
voidmemo_delete()
{
/*定义文件指针*/
FILE*fp;
/*定义变量*/
inti=0,t,choice,count=0;
structdate_messagetemp1={0,0,0,"\0"};
structdate_messagetemp2;
/*确认信息*/
printf("确认要删除当日备忘吗(y/n)?
");
/*如果输入y的话删除*/
if(!
(getchar()=='y'||'Y'))
{
printf("未删除该日任何备忘\n");
getch();
system("cls");
exit(0);
}
printf("
(1)删除单条备忘or
(2)删除当日所有备忘?
\n请输入1或2进行选择\n");
scanf("%d",&choice);
switch(choice)
{
case1:
printf("请输入要删除第几条备忘\n");
/*输入要删除第几条备忘*/
scanf("%d",&t);
if(!
(t>0&&t<=count_memo))
{
printf("输入错误!
该次操作失败!
");
getch();
system("cls");
exit(0);
}
/*打开文件*/
if((fp=fopen("calender.txt","rb+"))==NULL)
{
printf("打开文件失败\n\n");
return;
}
/*在文件中查找输入的年月日的信息*/
while
(1)
{
fseek(fp,i*sizeof(structdate_message),0);
if((fread(&temp2,sizeof(structdate_message),1,fp))!
=1)break;
if((temp2.year==date.year)&&(temp2.month==date.month)&&(temp2.day==date.day))
{
count++;
if(count==t)
{
fseek(fp,i*sizeof(structdate_message),0);
/*将空的覆盖上去*/
fwrite(&temp1,sizeof(structdate_message),1,fp);
break;
}
}
i++;
}
printf("单条备忘删除成功!
\n");
getch();
system("cls");
fclose(fp);
break;
case2:
/*打开文件*/
if((fp=fopen("calender.txt","rb+"))==NULL)
{
printf("打开文件失败\n\n");
return;
}
/*在文件中查找输入的年月日的信息*/
while
(1)
{
fseek(fp,i*sizeof(structdate_message),0);
if(fread(&temp2,sizeof(structdate_message),1,fp)!
=1)break;
if((temp2.year==date.year)&&(temp2.month==date.month)&&(temp2.day==date.day))
{
fseek(fp,i*sizeof(structdate_message),0);
fwrite(&temp1,sizeof(structdate_message),1,fp);
}
i++;
}
printf("当日所有备忘删除成功!
\n");
getch();
system("cls");
fclose(fp);
break;
default:
printf("输入错误!
操作失败!
");
getch();
system("cls");
exit(0);
}
}
memo_delete_all模块实现
1算法思想
从文件开头开始,每次将一个空结构体覆盖上已经存在的结构体,直到文件无法继续读取为止。
2具体实现
(关键代码)
/*全部备忘删除*/
voidmemo_delete_all()
{
/*定义文件指针*/
FILE*fp;
/*定义变量*/
inti=0;
structdate_messagetemp1={0,0,0,"\0"};
struct
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 万年历 课程设计