c语言实现万年历(大一大作业)(可查农历,节假日,周几,切换年月显示)(昨天交作业,今天上传(狗头))(萌新,如有问题,请多谅解)(使用dev c++)

本文主要是介绍c语言实现万年历(大一大作业)(可查农历,节假日,周几,切换年月显示)(昨天交作业,今天上传(狗头))(萌新,如有问题,请多谅解)(使用dev c++),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

这篇文章本意只是为了大家的万年历的实现方式提供一种思路,代码本身并不成熟,需要源代码的同学,本人已经上传到网站上了,设置的免费下载,csdn本身设置的免费下载需要做任务,但是绝对是可以下载的,请不要私信问作者资源需要付费下载的问题。并且文件在dev-c++环境下是可以运行的。如果你不会解压当我没说。字体重叠是因为没有全屏,或者屏幕缩放率不为100%造成的,请自行百度修改。

重新上传了资源,正在审核,为了方便大家 ,评论区也添加了百度云盘链接

一、先看效果图

1.年度显示

2.月度显示

3.查询日

二、思路及代码实现

       做这个程序我个人的思路是“查询日→→→查询月→→→查询年”这样的流程。因为我作业老师要求英文注释,我发到CSDN里面改成了中文,所以代码里面可能会有没删干净的英文注释。

1.查询周几

       查询日需要做的就是可以计算出需要查询的日期是周几,以及农历日期,和节假日。我个人认为农历日期的查询是最难做的,因为它的算法乱七八糟的,我这里用了一种比较取巧的方式。

             先说查询周几吧,这个应该都会,我就比较粗糙说一下。

a.确定基准。

我们以2000年1月1日作为基准,这一天是周六,冬月廿五,元旦。如果你想查之前的日子,那么你就把基准往前定。

b.计算要查的日期与基准所差的天数

这个部分的核心比较简单,只需要会判断中间每个年份是不是闰年,最后一年每个月都有几天,然后加起来就可以了。

//判断闰年
int leapyear (int y){int i=0;if(y%100==0){        //年份在可以被100整除的情况下必须被400整除才算闰年if(y%400==0){i=1;}} else {if (y%4==0){i=1;}}return i;   //如果是闰年就返回1 平年就返回0}
int week (int y,int m,int d){   //y年 m月 d天int i,j,w,sum1,sum2;        //w 周几int a[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};sum1=0;sum2=0;w=6;                        //基准那天是周六 if(leapyear(y)==1){a[2]=29;                //如果是闰年那么2月就有29天}     for(i=1;i<m;i++){sum2+=a[i];}    sum2+=d;                   //这时候是最后一年过了多少天sum1+=sum2;for(j=2000;j<y;j++){if(leapyear(j)==1){sum2=366;}   else {sum2=365;}sum1+=sum2;             //加上中间每年的天数}       sum1+=w;sum1-=1;				 //2000年1月1日已经过去了w=sum1%7;return w;               //把周几返回去  
}

c.需要打印周几的时候使用的函数


void printweek(int w){    //这个w是上个函数返回的wswitch(w)        {case 0:printf("周日");break;case 1:printf("周一");break;case 2:printf("周二");break;case 3:printf("周三");break;case 4:printf("周四");break;case 5:printf("周五");break;case 6:printf("周六");break;}}

 2.查询农历

农历的数据都是南京紫金山天文台历算室算出来的,有的节气是精确到时辰的,我弄了好长时间都不太会,所以我网上找了一个农历数据表。把他变成了txt文本,只保留了需要的农历日期。

 这是原来的文本

我改过后的

因为我们老师只要求常见的节假日,那些节气不做要求,我都去掉了,只留下了农历日期,节假日单独出一个函数。

然后农历闰x月我是直接在月前面加了一个3

比如闰5月就会变成35,闰冬月会变成311

把农历也变成数字是因为txt读取中文的时候可能会出错,我的作业肯定要求稳(狗头

此外因为我的农历是取决于我这个txt的范围的,如果你想扩大查询范围,你要先找到足够大的农历数据。

这个读取主要是使用

ch=fgetc(p);t=atoi(a);switch(x);这三个代码实现的。      

//注释看的时候要和修改后的txt文档结合看
void lunarcalendar(int y,int m,int d,int *p1,int *p2)    //y 年 m 月 d 天 p1指向lm即农历月 p2指向农历天
{int i,t,z,q;char a[10]={0};                                      //这个是用来存储和年份有关的字符的          
字符定义范围搞大点没什么影响char b[10]={0};                                      //这个是用来存储和月份有关的字符的   char c[40]={0};                                      //这个是用来存储和天份有关的字符的i=0;t=0;                                                  //atoi转化出来的数字年份q=0;                                                  //atoi转化出来的数字月份z=0;                                                    //atoi转化出来的数字天FILE*p;char ch;if((p=fopen("calendar.txt","r"))==NULL)                //打开txt文本{printf("ERROR\n");}for(; ;){                                            //这里开始一个循环for(;ch!='a';){                                  //持续不断地读入字符,读到“a”的时候进行下一步ch=fgetc(p);	}for(i=0;i<10;i++){a[i]=0;                                     //每次都想先把储存年份有关的字符都归零,这步很关键}for(i=0;;){	ch=fgetc(p);if(ch!='/'){                                //将字符依次赋值给字符数组,直到读到“/”的时候停止赋值a[i]=ch;i++; }else {break;}	}t=atoi(a);                                     //把字符年份变成数字年份并赋值		for(i=0;i<10;i++){                             //月份初始化,后面和年份操作相同b[i]=0;}for(i=0; ;){	ch=fgetc(p);if(ch!='/'){   b[i]=ch;i++;}else {break;}	}q=atoi(b);                                     //换成数字月份for(i=0;i<40;i++){c[i]=0;        }for(i=0;;){	ch=fgetc(p);if(ch!=','){   c[i]=ch;i++;}else {break;}	}z=atoi(c);                                    //换成数字天数if(t==y){if(q==m){if(z==d){break;                            //当年月日都和你想查的对应上之后,再进行下一部,否则会持续不断进行下去,如果你查了txt中不存在的月份,那么就会出bug,程序不会显示结果}}}				} for(i=0;i<10;i++){b[i]=0;                                    //初始化数组,现在这个数组用来储存农历月份}for(i=0;i<40;i++){c[i]=0;                                    //初始化数组,现在这个数组用来储存农历日期}	for(i=0;;){      ch=fgetc(p);if(ch!=','){                                   //读入农历月份b[i]=ch;i++;} else{break;}}q=atoi(b);                                       //转化为数字农历月份for(i=0;;){ch=fgetc(p);if(ch!=','){                                 //读入农历天数				c[i]=ch;i++;}else{break;}}z=atoi(c);                                      // 转化为数字农历天数fclose(p);                                             //关闭txt文件*p1=q;*p2=z;                                            //用指针赋值,这样就可以把结果弄出函数
}

可能有人看见代码,会问:“为什么每次读入字符前初始化字符数组很重要?”

for(i=0;i<10;i++){
            a[i]=0;
        }

因为每次程序都在读入年月日,不匹配的时候重新进行循环(循环的时候读入并不会初始化),所以这个循环势必要循环很多次,因此不进行初始化的时候 a[1],a[2],a[3],a[4]其实都是有值的,读入年份的时候不受影响,因为年都是四位数,但是读入月份的时候,如果不进行初始化,可能当你读到1月,并进行赋值,通过atoi转换到数字的时候会变成12月,这是因为a[2]的赋值在上一个循环读入12月的时候被赋值了12中的2,这次只读入了1个数字但是a[2]不是0,atoi读到的还是12,转化出来的数字就还是12.

void lunarcalendarmonth(int lm)
//lm 是p1指向的变量,农历月份
{switch(lm){case 1:printf("正月");break;case 2:printf("二月");break;case 3:printf("三月");break;case 4:printf("四月");break;case 5:printf("五月");break;case 6:printf("六月");break;case 7:printf("七月");break;case 8:printf("八月");break;case 9:printf("九月");break;case 10:printf("十月");break;case 11:printf("冬月");break;case 12:printf("腊月");break;case 31:printf("闰正月");break;case 32:printf("闰二月");break;case 33:printf("闰三月");break;case 34:printf("闰四月");break;case 35:printf("闰五月");break;case 36:printf("闰六月");break;case 37:printf("闰七月");break;case 38:printf("闰八月");break;case 39:printf("闰九月");break;case 310:printf("闰十月");break;case 311:printf("闰冬月");break;case 312:printf("闰腊月");break; }
}
void lunarcalendarday(int ld)             
//ld是上上个函数p2所指向的变量,是农历天数
{switch(ld){case 1:printf("初一");break; case 2:printf("初二");break; case 3:printf("初三");break; case 4:printf("初四");break; case 5:printf("初五");break; case 6:printf("初六");break; case 7:printf("初七");break; case 8:printf("初八");break; case 9:printf("初九");break; case 10:printf("初十");break; case 11:printf("十一");break; case 12:printf("十二");break; case 13:printf("十三");break; case 14:printf("十四");break; case 15:printf("十五");break; case 16:printf("十六");break; case 17:printf("十七");break; case 18:printf("十八");break; case 19:printf("十九");break; case 20:printf("二十");break; case 21:printf("廿一");break; case 22:printf("廿二");break; case 23:printf("廿三");break; case 24:printf("廿四");break; case 25:printf("廿五");break;case 26:printf("廿六");break; case 27:printf("廿七");break;case 28:printf("廿八");break;case 29:printf("廿九");break; case 30:printf("三十");break;   }
}

3.查询节假日

做到这里的时候,我们已经可以查出一天的周几,以及农历信息了,然后可以做出一个查询节假日的功能。给出的代码写法只可以查固定日期的节假日,如果想查二十四节气这种的则需要上一步的txt文本进行修改,添加数据,并且对读取代码做一些修改。

int festival(int y,int m,int d,int lm,int ld,int mod) //mod 是两个模式,输入1是这一天如果有节假日就只输出一个。主要用来查询整个月的时候 。输入2 是如果这一天有多个节假日,所有的都会输出。主要用于查询天
{int count=0;                                       //count记录这一天有几个节假日color(3);                                          //一般的节日输出颜色变为蓝色if(m==1){if(d==1){printf("元旦");count++; }}if(m==2){if(d==14){if(count!=0){if(mod==1){goto end;                           //mod 1 情况下遇到第二个节日直接结束这个函数,}printf("|");                            //mod2下有多个节日用“|”分割}printf("情人节");count++;                                    //Add one to the number of festivals}}end:color(7);	                                        //节日输出之后的输出字符颜色变为白色return count;                                     //把今天有几个节日传回去
}

这里的color函数是自己定义的一个函数,可以改变输出字符的颜色。

0 = 黑色 8 = 灰色
1 = 蓝色 9 = 淡蓝色
2 = 绿色 A = 淡绿色
3 = 浅绿色 B = 淡浅绿色
4 = 红色 C = 淡红色
5 = 紫色 D = 淡紫色
6 = 黄色 E = 淡黄色
7 = 白色 F = 亮白色

#include <windows.h>                                                //定义的时候加上这行void color(int x) if(x>=0&&x<=15){SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), x);}else{color(7);
}

 4.按月输出

按照月输出的时候,我们已经解决了最复杂的农历,现在只需要设置输出的位置就可以解决这个问题。

按月输出的核心难题是光标的移动。这里使用和color()函数相同的定义方法。

我们只需要会用这个函数就行了,万年历并不需要我们有深入的理解。(其实我也不会,我只是一个废物大学生)

#include <windows.h>
int wherex()
{CONSOLE_SCREEN_BUFFER_INFO pBuffer;GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &pBuffer);return (pBuffer.dwCursorPosition.X+1);
}
//得到光标的x坐标
int wherey()
{CONSOLE_SCREEN_BUFFER_INFO pBuffer;GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &pBuffer);return (pBuffer.dwCursorPosition.Y+1);
}
//得到光标的y坐标void gotoxy(int x,int y) 
{COORD c;c.X=x-1;c.Y=y-1;SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),c);
} 
//移动光标到指定位置


void month (int y ,int m){int d,ld,lm,*p1,*p2;d=1; ld=25;lm=11;p1=&lm;p2=&ld;//上面几个数的定义和之前的函数一样,注意不要把y当成坐标yint i,j,w,z,x1,y1,x2,y2,y3,t;t=0;d=1;                                                //输出月从1号开始(废话)int a[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};  if(leapyear(y)==1){a[2]=29;}                                                   //把这年的二月变成正确的天数,输出年的时候有用。w=week(y,m,d);                                      //利用函数求出这天是周几.z=wherex();                                         //得到现在光标的x坐标z+=5;                                               //记录的数据加5,可以根据自己的电脑进行修改gotoxy(z,wherey());                                 //将光标向右移动5,输出月的时候可以与左边流出空隙,这里可以忽略      printf("-----------------------------------------------");//分割线gotoxy(z,wherey()+1);                                //换行的时候不要简单使用“\n”,输出月的时候没有影响,但是会对年产生影响printf("                %d年%d月",y,m);              //月份头gotoxy(z,wherey()+1);                                //利用函数进行换行printf("-----------------------------------------------");//分割线gotoxy(z,wherey()+1);                                //换行printf("周日   周一   周二   周三   周四   周五   周六 ");gotoxy(z,wherey()+2);                                //一次换两行,留出空隙,使输出结果美观一些for(i=0,j=0;i<w;i++,j++){printf("       ");}                                                    //利用空格将第一天与周几对齐for(d=1;d<=a[m];d++,j++){lunarcalendar(y,m,d,p1,p2);                     //先查一下这个农历信息x1=wherex();                                          y1=wherey();                                    //记录现在输出数字时光标的位置if(d<10){printf("  %d    ",d);}else{printf(" %d    ",d);}                                               //为了美观留有空格,并输出x号x2=wherex();y2=wherey();                                //记录第二个坐标gotoxy(x1,y1+1);                            //往数字的下一行相同位置进行移动光标t=festival(y,m,d,lm,ld,1);//输出有颜色节日if(t==0){color(8);if(ld==1){lunarcalendarmonth(lm);}else{lunarcalendarday(ld);}//如果没有节日就输出灰色的农历日,但如果则这一天是初一,就输出月份,这样才能知道农历是几月(比如正月初一就输出正月 正月初二就输出初二)(老师要求的真细)}color(7);//之后的输出内容变成白色gotoxy(x2,y2);                                //把坐标移到下一个数字应该开始的地方													if(j==6){if(d<a[m]){gotoxy(z,wherey()+3);j=-1;}}}
//如果这一行已经满了,并且这一个月还没有结束,那就换行。gotoxy(z,wherey()+2);                                //这个月日期都结束后,光标移到下一个分割线位置printf("-----------------------------------------------");//分割线gotoxy(z,wherey()+1);                                //换行
}


以下就是输出一个月的日历的主代码

printf("请根据'200001'输入年月\n");
scanf("%4d%2d",&y,&m);
month(y,m);          //打出这一个月的日历
gotoxy(1,wherey());//让光标靠左

 4.按年输出 

当我们实现按月输出后,按年输出的代码就变得简单了起来,只需要一个简单的for循环加移动光标等就可以了。

按月输出的时候之所以不直接用换行符是因为按年输出的时候,一旦换行,这个月的输出结果就会跑到上个月数据的地方,有兴趣的可以试试直接用换行符会发生什么(狗头)。

void year(int y)
{int x1,y1,x2,y2,max;max=0;                                                            //纪录每个月分割线最靠下的y坐标int m=1;int count=0;int a[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};if(leapyear(y)==1){a[2]=29;}for(m=1;m<13;m++){x1=wherex();y1=wherey(); month(y,m);if(max<wherey()){max=wherey();  }                                                            //纪录每个月分割线最靠下的y坐标count++;if(count%4==0){x2=wherex();y2=wherey();gotoxy(1,max+3);                                    //为了排版,max是必要的,要不然容易挤掉其他月份的输出结果}else{gotoxy(x1+58,y1);                                    //将光标移到上个月开始的右边58字符的位置}}                                
//每四个月换一次行变成4*3的排列方式,自己也可以改成3*4或其他的}

三、总结

                万年历想要做细,想要考虑的细节还真不少。这是我的大一作业,也是第一个真正意义上的程序,所以肯定有很多没必要的代码,很多不够简便的方法,希望各位大佬看到之后多多谅解。

这篇关于c语言实现万年历(大一大作业)(可查农历,节假日,周几,切换年月显示)(昨天交作业,今天上传(狗头))(萌新,如有问题,请多谅解)(使用dev c++)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/497344

相关文章

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

作业提交过程之HDFSMapReduce

作业提交全过程详解 (1)作业提交 第1步:Client调用job.waitForCompletion方法,向整个集群提交MapReduce作业。 第2步:Client向RM申请一个作业id。 第3步:RM给Client返回该job资源的提交路径和作业id。 第4步:Client提交jar包、切片信息和配置文件到指定的资源提交路径。 第5步:Client提交完资源后,向RM申请运行MrAp

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

好题——hdu2522(小数问题:求1/n的第一个循环节)

好喜欢这题,第一次做小数问题,一开始真心没思路,然后参考了网上的一些资料。 知识点***********************************无限不循环小数即无理数,不能写作两整数之比*****************************(一开始没想到,小学没学好) 此题1/n肯定是一个有限循环小数,了解这些后就能做此题了。 按照除法的机制,用一个函数表示出来就可以了,代码如下

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

第10章 中断和动态时钟显示

第10章 中断和动态时钟显示 从本章开始,按照书籍的划分,第10章开始就进入保护模式(Protected Mode)部分了,感觉从这里开始难度突然就增加了。 书中介绍了为什么有中断(Interrupt)的设计,中断的几种方式:外部硬件中断、内部中断和软中断。通过中断做了一个会走的时钟和屏幕上输入字符的程序。 我自己理解中断的一些作用: 为了更好的利用处理器的性能。协同快速和慢速设备一起工作

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传