一.作业题目
三天打鱼两天晒网
二.作业内容
中国有句俗语叫“三天打鱼两天晒网”。某人从2010年1月1日起开始“三天打鱼两天晒网”,问这个人在以后的某一天中是在“打鱼”还是“晒网”。
更新:加上文件测试
三.算法设计
1.检测输入时间的合法性
即年份需要不小于2010,月份不能大于12,日期不能大于31
2.设计函数用来判断闰年还是平年
闰年:能被4整除且不能被100整除或者能被400整除,闰年2月有29天
平年:2月28天
可以在算天数的函数中,定义一个二维数组来分开区别表示。
3.设计函数用来算2个时间之间的天数
3.1年份相同,月份相同,日期相减即可
3.2年份相同,月份不同。通过循环二维数组实现天数的累加,最后再加上本月的日期即可
3.3年份不同。
先算整年的天数进行累加,再算整月的天数进行累加,最后加上本月的日期
4.打鱼还是晒网
将天数除以5得余数
余数为1,2,3;则打鱼
余数为4,0;则晒网
代码如下:
#include <stdio.h>
#include <stdlib.h>
struct Date
{
int year;
int month;
int date;
};//声明结构体
int main(void)
{
struct Date maxDate;
int days,tag,a,b,c;
FILE *p,*f;
printf("请输入选择标志tag的值;tag为1是从键盘输入年月日,tag为0是从in.text中提取日期\n");
scanf("%d",&tag);
switch(tag)
{
case 0:
{
FILE *p=fopen("in.txt","r");//用只读的方式打开文件in.txt
FILE *f=fopen("out.txt","w");//用只写的方式打开文件out.txt
while(!feof(p))
{
fscanf(p,"%d %d %d",&a,&b,&c);//从文件in.txt中读取数据年月日
printf("%d年%d月%d日\n",a,b,c);
maxDate.year=a;
maxDate.month=b;
maxDate.date=c;
if (maxDate.year < 2010 || maxDate.month > 12 || maxDate.date > 31)
printf("输入数据有误,请重新输入\n");
else{
int Diff(struct Date maxDate);
days = Diff(maxDate) + maxDate.date;//将Diff函数返回的day天数再加上本月的日期,即为2个时间之间的天数
printf("天数为:%d\n", days);//将天数输出
int yu = days % 5;
switch (yu) //利用switch语句,判断打鱼or晒网
{
case 1:
case 2:
case 3:
printf("今天打鱼\n");
fprintf(f,"%d %s %d %s %d %s",a,"年",b,"月",c,"日");//将判断及结果写入out.txt中
fprintf(f,"%s","他这天在打鱼\n");//输出打鱼
break;
case 4:
case 0:
printf("今天晒网\n");//输出晒网
fprintf(f,"%d %s %d %s %d %s",a,"年",b,"月",c,"日");//将判断及结果写入out.txt中
fprintf(f,"%s","他这天在晒网\n");//输出晒网
break;
};
};
};
break;
};
case 1:{
printf("请输入年月日\n");
scanf("%d %d %d",&maxDate.year,&maxDate.month,&maxDate.date);
if (maxDate.year < 2010 || maxDate.month > 12 || maxDate.date > 31)
printf("输入数据有误,请重新输入\n");
else
{
int Diff(struct Date maxDate);
days = Diff(maxDate) + maxDate.date;//将Diff函数返回的day天数再加上本月的日期,即为2个时间之间的天数
printf("天数为:%d\n", days);//将天数输出
int n = days % 5;
switch (n) //利用switch语句,判断打鱼or晒网
{
case 1:
case 2:
case 3:
printf("今天打鱼");//输出打鱼
break;
case 4:
case 0:
printf("今天晒网");//输出晒网
break;
};
};
};
};
};
int isPrime(int year) //检查是否为闰年,闰年返回1,平年返回0
{
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
return 0;
else
return 1;
};
int Diff(struct Date maxDate) //计算日期
{
int day = 0, i, j;
static int Month[2][13] = { {0,31,29,31,30,31,30,31,31,30,31,30,31},{0,31,28,31,30,31,30,31,31,30,31,30,31} };//设计一个二维数组来分开区别闰年和平年
if (maxDate.year == 2010)//将年份,月份都相同 和 年份相同,月份不同的两种情况进行合并
for (i = 1; i < maxDate.month; i++)//利用for循环二维数组,实现整月份天数累加
day += Month[1][i];
else //年份不同的情况相对复杂
{
for (j = 2010; j < maxDate.year; j++) //先从2010年向后到年份的前一年进行推算循环
day += isPrime(j) ? 365 : 366; //利用双目条件运算符和判断闰年还是平年的函数,进行整年份的天数累加
for (i = 1; i < maxDate.month; i++) //实现整月份的天数累加
day += Month[isPrime(maxDate.year)][i];
};
return day;
};
注意:输入in.txt文件和输出out.txt文件需要和.cpp文件放到一个工程中
四.心得体会
这个题目主要得难度是在天数得计算上,我开始想通过判断闰年就给day一个366,平年就给一个365,但是后来发现,如果年份是2011之后得年份,无法实现循环累加。然后通过查资料看到别人通过一个双目条件运算符?:对闰年平年进行0或1的标记,再结合for循环就可以很巧妙的实现整年份的累加。对于整月份的天数计算,我开始是定义了2个一维数组,然后根据闰年和平年来选择累加,这样也可以实现,不过比较繁琐,还需要写一个通过闰年平年标记选择用哪个数组的语句。看了别人的代码,觉得人家设计的很巧妙,只需要一个二维数组就可以了,对于闰年平年的标记0或1,再进行整年份的运算已经定义过了,就不需要再定义一边,而且为了方便在第一个数31前面加了一个0,这样处理之后,在后面循环的时候就不用再考虑数组的第一个索引值默认为0这个问题了。
在第一次运行的时候我发现天数总是不对,经过调试发现,通过scanf给值的时候,年份的值是对的,但是月份和日期都没有给上,都是0.原来的语句是这个样子scanf(“%d,%d,%d”,&maxDate.year,&maxDate.month,&maxDate.date); 后来将“”中的逗号改成空格之后就成功了。
代码就在Dev中运行成功了,然后我又把代码放到VS2019中跑一遍,结果显示scanf错误提示C4996,经过百度,已经将此问题解决,并整理了4种解决方案发布到了博客。
hexo+github博客:https://suyufan.github.io/