C語言輸出格式工整的日歷——2乘6樣式(詳見本文)


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

文章末尾的完整代碼如不能在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的范圍),不過還是有點參考價值的。如果對你有幫助的話不妨支持一下,非常感謝🙏


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM