本篇博客有更新!!!更新后效果图如下:

文章末尾的完整代码如不能在Dev-C++上完好运行,出现如下问题:

E:\Dev-Cpp\源代码\万年历.c [Error] 'for' loop initial declarations are only allowed in C99 or C11 mode

原因及解决办法:http://bbs.bccn.net/thread-436527-1-1.html

回归正题:更新内容为第三问中第2小问的代码实现(超详细注释)

最近帮朋友做一些C语言的练习题,期间遇到了个比较有意思的题目,意在考察模块化程序设计,大致要求如下:

电子万年历:

1、编写函数int isleapyear(int year);判某年是否为闰年,如该年为闰年返回1,否则返回0。编写主函数输入年份给出该年是否为闰年。

2、编写函数int dayofmonth(int year ,int month);计算某年某月有几天。主函数中输入任意的年和月,给出此年该月有几天。

3、编写万年历。请利用上述1、2已编写的函数和下边已提供的函数来完成:

(1)输入年打印出此年的日历。

(2)输入年和月打印给出此年该月的日历。

 1 /*参考代码*/
2 int firstdayofyear(int year) /*求某年的第一天是星期几*/
3
4 { int i;
5
6 long n,days=year;
7
8 days=days*365; /* printf("\n%ld",days);*/
9
10 for(i=1;i<year;i++)days=days+isleapyear(i); /*printf("\n%ld",days);*/
11
12 n=days%7;
13
14 return n;
15
16 }
17
18 int firstdayofmonth(int year, int month) /* 求某年某月的第一天是星期*/
19
20 { int i,days=0, weekdays;
21
22 weekdays=firstdayofyear(year);
23
24 for(i=1;i<month;i++)days+=dayofmonth(yeari);
25
26 return (days+weekdays)%7;
27
28 }

这道题并不算困难(给出了一些参考代码),而且根据上面给出的要求也不难得到如下思路:

第一问:根据闰年计算的规则编写一个闰年判断函数。

这里我采用的是格里高利闰年规则:

1.公元年份非4的倍数,为平年。

2.公元年份为4的倍数但非100的倍数,为闰年。

3.公元年份为100的倍数但非400的倍数,为平年。

4.公元年份为400的倍数,为闰年。

转换为C语言代码形式就成了下面这样子:

1 int isLeapyear(int year)
2 {//判断否为闰年
3 //满足上述规则2或4,返回1,否则返回0
4 return ((year%100!=0&&year%4==0) || year%400==0) ? 1 : 0;
5 }

第二问:编写函数计算某年某月有几天。

由于每一年的天数差别只在二月,而二月份天数的多少又受闰年的影响,所以我们只需要对二月进行特殊判断即可。可以利用第一问已经写过的函数,完成第二问,代码如下:

 1 int dayOfMonth(int year, int month)
2 {//计算某年某月的天数
3 int x;//天数
4 switch(month){
5 case 1:case 3:case 5:case 7:case 8:case 10:case 12:
6 x=31;
7 break;
8 case 2:
9 //闰年2月29天,平年28天
10 x=isLeapyear(year) ? 29 : 28;
11 break;
12 case 4:case 6:case 9:case 11:
13 x=30;
14 break;
15 default: break;
16 }
17 return x;
18 }

第三问:利用已知函数,根据输入打印出相应的年或月的日历。

重点在于第一小问,只要我们能正确输出某一月的日历,那么输出某年的日历就相当于依次输出1~12月的日历。参考代码中已经给出了两个非常有用的函数,分别是:

  • int firstdayofyear(int year) /*求某年的第一天是星期几*/
  • int firstdayofmonth(int year, int month) /* 求某年某月的第一天是星期*/

这里我的想法是先利用firstdayofmonth这个函数计算出某年某月第一天是星期几,然后计算出该月有多少天,最后利用循环输出,为了美观每七天换行一次。代码如下:

 1 void displayMonth(int year, int month)
2 {
3 int start,days;//该月第一天是周几 该月的天数
4 start=firstdayofmonth(year,month);
5 days=dayOfMonth(year,month);
6 if(start==0)//如果等于零说明第一天刚好是星期天,要转换一下
7 start=7;
8 printf("一\t二\t三\t四\t五\t六\t日\n");
9 for(int i=1;i<days+start;++i){
10 if(i<start)//没有到该月第一天之前,输出空白
11 printf(" \t");
12 else//从1开始依次输出日期
13 printf("%2d\t",i-start+1);
14 if(i%7==0)//满七天换行
15 printf("\n");
16 }
17 }

第二小问就简单了,循环依次打印每月的日历就是某年的日历,代码如下:

1 void displayYear(int year)
2 {//循环调用打印月份的函数输出某年的日历
3 for(int i=1;i<=12;++i){
4 printf("%d月:\n",i);
5 displayMonth(year,i);
6 printf("\n");
7 }
8 }

由于初版整体打印效果比较low,这次又进行了改进。思路为每次输出一行的内容,即第i月和第i+6月(0<i<7)的日期,代码实现如下(效果图见文章开头):

 1 void displayYear(int year) {
2 //左边月的天数 右边月的天数 左边月份的第一天 右边月份的第一天
3 int daysl,daysr,sl,sr;
4 //二乘六的日历表外循环共执行6次
5 for(int i=1; i<=6; ++i) {
6 //打印星期栏
7 printf(" |%2d Sun Mon Tue Wen Thu Fri Sat %2d Sun Mon Tue Wen Thu Fri Sat |\n",i,i+6);
8 //初始上述变量,m和n分别记录该月当前应输出的日期
9 int m=1, n=1;
10 sl=firstdayofmonth(year,i);
11 daysl=dayOfMonth(year,i);
12 sr=firstdayofmonth(year,i+6);
13 daysr=dayOfMonth(year,i+6);
14 //对于不是第一天不是星期天的日期要做加一变化
15 sl = sl > 0 ? sl+1 : 0;
16 sr = sr > 0 ? sr+1 : 0;
17 //该循环每次输出具体的两个月份的日历,如1/7月,2/8月……
18 while(m < sl+daysl || n < sr+daysr) {
19 //每次循环都使用一个数组记录要输出的内容,这个大小只是为了输出美观设置的
20 //初始化值为0
21 int out[40]= {0};
22 //-1代表要输出表示边界的"|"符号
23 out[1] = -1;
24 out[39] = -1;
25 //输出每一行的循环 ,p,q记录应输出的位置
26 for(int p=5, q=24; p<18; p+=2, q+=2, ++m, ++n) {
27 //左边的月份
28 if(m < sl+daysl) {
29 if(m<sl)//未到该月第一天,令值为-2,表示输出连续的三个空格
30 out[p]=-2;
31 else //记录正确日期的值
32 out[p]=m-sl+1;
33 } else
34 out[p]=-2;//如果该月日期输出完毕,其余的部分为了格式一致,要用空格补全
35
36 //右边的月份,原理同上
37 if(n < sr+daysr) {
38 if(n<sr)
39 out[q]=-2;
40 else
41 out[q]=n-sr+1;
42 } else
43 out[q]=-2;
44 }
45 //按照上述数组保存值所代表的意义打印出来
46 for(int t=0; t<40; ++t) {
47 if(out[t]==-1)
48 printf("|");
49 else if(out[t]==-2)
50 printf(" ");
51 else if(out[t]==0)
52 printf(" ");
53 else
54 printf("%3d",out[t]);
55 }
56 printf("\n");
57 }
58 }
59 }

最后把他们整合到成一个程序,代码如下:

  1 #include<stdio.h>
2
3 /**
4 * 目前使用的格里高利历闰年规则如下:
5 * 1.公元年份非4的倍数,为平年。
6 * 2.公元年份为4的倍数但非100的倍数,为闰年。
7 * 3.公元年份为100的倍数但非400的倍数,为平年。
8 * 4.公元年份为400的倍数,为闰年。
9 */
10
11 //函数声明
12 int isLeapyear(int year); //判断是否为闰年
13 int dayOfMonth(int year, int month); //计算某年某月的天数
14 int firstdayofyear(int year); //求某年的第一天是星期几
15 int firstdayofmonth(int year, int month);//求某年某月的第一天是星期几
16 void displayYear(int year); //打印某年的日历
17 void displayMonth(int year, int month); //打印某年某月的日历
18
19 int main() {
20 int year,month;
21 printf("请依次输入年份和月份:\n");
22 scanf("%d%d",&year,&month);
23 if(year<=0 || month<1 || month>12)
24 printf("输入不合法!");
25 else {
26 if(isLeapyear(year))
27 printf("是闰年,该月有%d天",dayOfMonth(year, month));
28 else
29 printf("是平年,该月有%d天",dayOfMonth(year, month));
30 printf("\n%d年的日历如下:\n",year);
31 printf("\n +---------------------------%d年的年历--------------------------+\n",year);
32 displayYear(year);
33 printf(" +-----------------------------------------------------------------+\n");
34 }
35 //displayMonth(year,month);
36 return 0;
37 }
38
39 int isLeapyear(int year) {
40 //判断否为闰年
41 //满足上述规则2或4,返回1,否则返回0
42 return ((year%100!=0&&year%4==0) || year%400==0) ? 1 : 0;
43 }
44
45 int dayOfMonth(int year, int month) {
46 //计算某年某月的天数
47 int x;//天数
48 switch(month) {
49 case 1:
50 case 3:
51 case 5:
52 case 7:
53 case 8:
54 case 10:
55 case 12:
56 x=31;
57 break;
58 case 2:
59 //闰年2月29天,平年28天
60 x=isLeapyear(year) ? 29 : 28;
61 break;
62 case 4:
63 case 6:
64 case 9:
65 case 11:
66 x=30;
67 break;
68 default:
69 break;
70 }
71 return x;
72 }
73
74 int firstdayofyear(int year) {
75 //求某年的第一天是星期几
76 int i;
77 long days; //天数
78 days=year*365;//从0年到year年一共有多少天
79 for(i=1; i<year; i++) //加上闰年多出的天数
80 days=days+isLeapyear(i);
81 return days%7; //取余得出year年的第一天是星期几
82 }
83
84 int firstdayofmonth(int year, int month) {
85 //求某年某月的第一天是星期几
86 int i,days=0,weekdays; //天数 星期几
87 weekdays=firstdayofyear(year); //得出year年的第一天是weekdays
88 for(i=1; i<month; i++) //计算month月之前的天数days
89 days+=dayOfMonth(year, i);
90 return (days+weekdays)%7; //取余得出year年month月的第一天是星期几
91 }
92
93 void displayYear(int year) {
94 //左边月的天数 右边月的天数 左边月份的第一天 右边月份的第一天
95 int daysl,daysr,sl,sr;
96 //二乘六的日历表外循环共执行6次
97 for(int i=1; i<=6; ++i) {
98 //打印星期栏
99 printf(" |%2d Sun Mon Tue Wen Thu Fri Sat %2d Sun Mon Tue Wen Thu Fri Sat |\n",i,i+6);
100 //初始上述变量,m和n分别记录该月当前应输出的日期
101 int m=1, n=1;
102 sl=firstdayofmonth(year,i);
103 daysl=dayOfMonth(year,i);
104 sr=firstdayofmonth(year,i+6);
105 daysr=dayOfMonth(year,i+6);
106 //对于不是第一天不是星期天的日期要做加一变化
107 sl = sl > 0 ? sl+1 : 0;
108 sr = sr > 0 ? sr+1 : 0;
109 //该循环每次输出具体的两个月份的日历,如1/7月,2/8月……
110 while(m < sl+daysl || n < sr+daysr) {
111 //每次循环都使用一个数组记录要输出的内容,这个大小只是为了输出美观设置的
112 //初始化值为0
113 int out[40]= {0};
114 //-1代表要输出表示边界的"|"符号
115 out[1] = -1;
116 out[39] = -1;
117 //输出每一行的循环 ,p,q记录应输出的位置
118 for(int p=5, q=24; p<18; p+=2, q+=2, ++m, ++n) {
119 //左边的月份
120 if(m < sl+daysl) {
121 if(m<sl)//未到该月第一天,令值为-2,表示输出连续的三个空格
122 out[p]=-2;
123 else //记录正确日期的值
124 out[p]=m-sl+1;
125 } else
126 out[p]=-2;//如果该月日期输出完毕,其余的部分为了格式一致,要用空格补全
127
128 //右边的月份,原理同上
129 if(n < sr+daysr) {
130 if(n<sr)
131 out[q]=-2;
132 else
133 out[q]=n-sr+1;
134 } else
135 out[q]=-2;
136 }
137 //按照上述数组保存值所代表的意义打印出来
138 for(int t=0; t<40; ++t) {
139 if(out[t]==-1)
140 printf("|");
141 else if(out[t]==-2)
142 printf(" ");
143 else if(out[t]==0)
144 printf(" ");
145 else
146 printf("%3d",out[t]);
147 }
148 printf("\n");
149 }
150 }
151 }
152
153 void displayMonth(int year, int month) {
154 int i,start,days;//自增变量 该月第一天是周几 该月的天数
155 start=firstdayofmonth(year,month);
156 days=dayOfMonth(year,month);
157 start = start > 0 ? start+1 : 0;
158 printf("\nSUN MON TUE WEN THU FRI SAT\n");
159 for(i=1; i<days+start; ++i) {
160 if(i<start) { //没有到该月第一天之前,输出空白
161 printf(" ");
162 } else //从1开始依次输出日期
163 printf("%3d ",i-start+1);
164 if(i%7==0)//满七天换行
165 printf("\n");
166 }
167 }

新版代码

  1 #include<stdio.h>
2
3 /**
4 * 目前使用的格里高利历闰年规则如下:
5 * 1.公元年份非4的倍数,为平年。
6 * 2.公元年份为4的倍数但非100的倍数,为闰年。
7 * 3.公元年份为100的倍数但非400的倍数,为平年。
8 * 4.公元年份为400的倍数,为闰年。
9 */
10
11 //函数声明
12 int isLeapyear(int year); //判断是否为闰年
13 int dayOfMonth(int year, int month); //计算某年某月的天数
14 int firstdayofyear(int year); //求某年的第一天是星期几
15 int firstdayofmonth(int year, int month);//求某年某月的第一天是星期几
16 void displayYear(int year); //打印某年的日历
17 void displayMonth(int year, int month); //打印某年某月的日历
18
19 int main()
20 {
21 int year,month;
22 printf("请依次输入年份和月份:\n");
23 scanf("%d%d",&year,&month);
24 if(year<=0 || month<1 || month>12)
25 printf("输入不合法!");
26 else{
27 if(isLeapyear(year))
28 printf("是闰年,该月有%d天",dayOfMonth(year, month));
29 else
30 printf("是平年,该月有%d天",dayOfMonth(year, month));
31 printf("\n%d年的日历如下:\n",year);
32 displayYear(year);
33 printf("%d年%d月的日历如下:\n",year,month);
34 displayMonth(year,month);
35 }
36 return 0;
37 }
38
39 int isLeapyear(int year)
40 {//判断否为闰年
41 //满足上述规则2或4,返回1,否则返回0
42 return ((year%100!=0&&year%4==0) || year%400==0) ? 1 : 0;
43 }
44
45 int dayOfMonth(int year, int month)
46 {//计算某年某月的天数
47 int x;//天数
48 switch(month){
49 case 1:case 3:case 5:case 7:case 8:case 10:case 12:
50 x=31;
51 break;
52 case 2:
53 //闰年2月29天,平年28天
54 x=isLeapyear(year) ? 29 : 28;
55 break;
56 case 4:case 6:case 9:case 11:
57 x=30;
58 break;
59 default: break;
60 }
61 return x;
62 }
63
64 int firstdayofyear(int year)
65 {//求某年的第一天是星期几
66 long days; //天数
67 days=year*365;//从0年到year年一共有多少天
68 for(int i=1;i<year;i++) //加上闰年多出的天数
69 days=days+isLeapyear(i);
70 return days%7; //取余得出year年的第一天是星期几
71 }
72
73 int firstdayofmonth(int year, int month)
74 {//求某年某月的第一天是星期几
75 int days=0,weekdays; //天数 星期几
76 weekdays=firstdayofyear(year); //得出year年的第一天是weekdays
77 for(int i=1;i<month;i++) //计算month月之前的天数days
78 days+=dayOfMonth(year, i);
79 return (days+weekdays)%7; //取余得出year年month月的第一天是星期几
80 }
81
82 void displayYear(int year)
83 {
84 for(int i=1;i<=12;++i){//循环调用打印月份的函数输出某年的日历
85 printf("%d月:\n",i);
86 displayMonth(year,i);
87 printf("\n");
88 }
89 }
90
91 void displayMonth(int year, int month)
92 {
93 int start,days;//该月第一天是周几 该月的天数
94 start=firstdayofmonth(year,month);
95 days=dayOfMonth(year,month);
96 if(start==0)//如果等于零说明第一天刚好是星期天,要转换一下
97 start=7;
98 printf("一\t二\t三\t四\t五\t六\t日\n");
99 for(int i=1;i<days+start;++i){
100 if(i<start)//没有到该月第一天之前,输出空白
101 printf(" \t");
102 else//从1开始依次输出日期
103 printf("%2d\t",i-start+1);
104 if(i%7==0)//满七天换行
105 printf("\n");
106 }
107 }

旧版代码

运行效果见下图(旧版):

  虽然说是万年历,但实际有点过于简单了(只显示公历),而且这个输入范围也有限制(不能超过int的范围),不过还是有点参考价值的。如果对你有帮助的话不妨支持一下,非常感谢

C语言输出格式工整的日历——2乘6样式(详见本文)的更多相关文章

  1. Ext.net Calendar 控件在有模板页的时候,模板页定义了TD的样式造成日历控件的样式丢掉

    Ext.net Calendar 控件在有模板页的时候,模板页定义了TD的样式造成日历控件的样式丢掉 解决方案 在本页面添加下面的样式 <style type="text/css&qu ...

  2. C语言输出格式总结

    转自:http://www.cnblogs.com/scbzljstudy/archive/2011/02/28/1966887.html 1 一般格式    printf(格式控制,输出表列)    ...

  3. C语言输出格式

    1 一般格式    printf(格式控制,输出表列)    例如:printf("i=%d,ch=%c\n",i,ch);    说明:    (1)“格式控制”是用双撇号括起来 ...

  4. c语言的简易日历

    用c语言编写的简易日历,代码如下: #include <stdio.h> int main(int argc, const char * argv[]) { // insert code ...

  5. Java:日历类、日期类、数学类、运行时类、随机类、系统类

    一:Calendar类 java.util 抽象类Calendar   1.static Calendar getInstance()使用默认时区和语言环境获得一个日历. 2. int get(int ...

  6. Android自己定义组件之日历控件-精美日历实现(内容、样式可扩展)

    需求 我们知道.Android系统本身有自带的日历控件,网络上也有非常多开源的日历控件资源.可是这些日历控件往往样式较单一.API较多.不易于在实际项目中扩展并实现出符合详细样式风格的,内容可定制的效 ...

  7. 日期 日历 时区 地区 格式化 API 案例 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  8. iOS中的日历

    iOS自带三种日历,公历.佛教日历和日本日历,要设置日历可以进入"设置-通用-语言与地区-日历"设置,我们中国使用的iPhone默认设置成公历.而泰国人使用的iPhone默认设置的 ...

  9. C C++输出格式 <转载>仅用于个人

    转载链接:C++ C C语言输出格式总结 1 一般格式    printf(格式控制,输出表列)    例如:printf("i=%d,ch=%c\n",i,ch);    说明: ...

  10. 01 语言基础+高级:1-5 常用API第二部分_day01.【Object类、常用API: Date类、System类、StringBuilder类】

    day01[Object类.常用API] 主要内容 Object类 Date类 DateFormat类 Calendar类 System类 StringBuilder类 包装类 java.lang.O ...

随机推荐

  1. JS --函数进阶 --手稿

  2. MySQL 获取所有表名、所有表结构

    获取所有表名 SELECT A.TABLE_SCHEMA '数据库', A.TABLE_NAME '表名', A.TABLE_ROWS '表记录行数', A.CREATE_TIME '创表时间', A ...

  3. 记一次 .NET某酒业业务系统 崩溃分析

    一:背景 1. 讲故事 前些天有位朋友找到我,说他的程序每次关闭时就会自动崩溃,一直找不到原因让我帮忙看一下怎么回事,这位朋友应该是第二次找我了,分析了下 dump 还是挺经典的,拿出来给大家分享一下 ...

  4. 只会建数据库怎么写API?database2api 能帮到你!

    database2api 意为 DataBase to API,即只要有数据库,就可以生成开放 API. database2api 是一款强大而便捷的工具,主要功能是依据现有的数据库自动生成开放的 A ...

  5. CF452C 题解

    洛谷链接&CF 链接 题目简述 有 \(m \times n\) 张牌,有 \(n\) 个种类,每个种类有 \(m\) 张,现在抽一张放回,再抽一张,求这张牌与第一张抽出的牌种类相同的概率. ...

  6. CF1883B Chemistry 题解

    原题传送门 思路: 如"aba","abba"这样的回文字符串, 每个字符的出现次数有以下两种情况: 1:全部是偶数(abba) 2:只有一个为奇数(aba) ...

  7. 1分钟了解HashSet的使用

    前言:刷leetcode的时候体验到hashset有多厉害了,用了他剪枝之后直接不爆超时了.速度大大滴快 使用方法 1.创建set对象Set<Integer>set=new HashSet ...

  8. 5/15课下作业:评价一下steam软件

    用户界面: 登录后会弹出特惠广告,广告内容可能不常用.主界面简洁方便,启动游戏,购买游戏,浏览社区,浏览自己内容一目了然 记住用户选择: 登录一次后会记住用户的账户密码,可以直接进行用户间的切换,会记 ...

  9. openeuler linux内核4.19安装(centos 同理)

    linux内核安装: 安装内核步骤 下载相应内核版本[我这里用的是linux-4.19.90.tar.gz] 下载网址:https://mirrors.edge.kernel.org/pub/linu ...

  10. 【VMware】 桥接网路发现无法Ping通原因

    解决方案参考: https://blog.csdn.net/weixin_33856370/article/details/92420910 设置好的同网段的三台虚拟机这次开机连不上网了 仔细发现VM ...