C/C++編程筆記:C語言編寫大學(xué)實驗課項目——萬年歷!全解
題目要求
編程實現(xiàn)萬年歷,要求:
可根據(jù)用戶輸入或系統(tǒng)日期進行初始化,如果用戶無輸入則顯示系統(tǒng)日期所在月份的月歷,并突出顯示當(dāng)前日期;
可根據(jù)用戶輸入的日期查詢,并顯示查詢結(jié)果所在月份的月歷,突出顯示當(dāng)前日期,并提示是否閏年
對任何不合法輸入數(shù)據(jù),拒絕查詢并進行提示。

思路分析
可將思考、編程劃分為以下幾個模塊:
如何通過已有日期和星期推算要求的日期的星期?
如何整齊地輸出月歷?
如何獲取系統(tǒng)時間?
在有余力的前提下,如何美化界面?
下面對上面的幾個問題給出粗略的概述。
具體實現(xiàn)和技巧性地東西參考后文代碼。
問題1 日期推算
眾所周知,需要推算日期的模擬題都是毒瘤題
日期推算的算法有很多,這里只給出我的思路:
推出差了多少天。
用數(shù)學(xué)公式推出星期。
這條公式是?(w+d)mod7(w+d)mod7?,d 表示差的天數(shù),w 表示原本是星期幾。
我采用的是標(biāo)準的?0 表示 Sun.?而 6 表示 Sat. 的方法。
time.h 自帶的 tm_wday 就是用這種方式表示的。
需要注意的是?C 與 C++ 對負數(shù)取模的特(sha)殊(bi)性?,所以為了求出正確的結(jié)果,我們要采用一點小技巧。
if(w1+d<0) w2=(w1+d)+(-w1-d)/7*7+7;?
似乎也可以在推出天數(shù)后乘上86400減一下然后扔給 localtime() 去推星期。
但是你連天數(shù)都推出來了,直接算不香嗎。而且既然是萬年歷,秒數(shù)太大爆了怎么辦
接下來讓我們考慮如何推算差了多少天。
我為了方便計算,所有的推算都以2020年1月1日星期三為基準。
由一個基準來推的化可以省去很多麻煩。
首先,第一種方法是暴力模擬。一年一年地推、一月一月地推、一天一天地推。
我在代碼中注釋掉的就是暴力模擬法。
這個沒什么好講的,閏年就差 366 天,否則差 365 天。
年推到了就推月,實現(xiàn)把每個月份的天數(shù)打個表,別忘了特判二月就行。
你也可以不像我那樣偷懶一個一個月推,使用?前綴和數(shù)組+閏年特判?也行。但是每次查詢最多就推 12 個月,一個月一個月推也差不了多少。
這點時間肉眼是看不出來的。所以隨便吧。
天數(shù)就沒什么好說的,自己隨便想兩個同年同月的日期看看差幾天,很快就能看出是直接拿日期相減了。
其實,我們不難發(fā)現(xiàn),年份可以不用一年一年模擬,可以用數(shù)學(xué)公式算。
現(xiàn)在我們要算?A年1月1日 到 B年1月1日?經(jīng)過了幾個閏年。
以 A < B 為例
直接拿 (B-A)/4 來算閏年個數(shù)這種玄學(xué)的事情我是不會干的。我希望求出的閏年個數(shù)是絕對準確的。
因此可以這樣來:
我們知道 x/4 可以表示小于等于 x 的正整數(shù)中 4 的倍數(shù)的個數(shù)。
我們需要求經(jīng)過的閏年的個數(shù),只需要知道區(qū)間 [A,B-1] 中 4、100、400 的倍數(shù)的個數(shù)就行了。
( 因為我考慮的是 1月1日 ,如果考慮 12月31日 的話,應(yīng)該變?yōu)?[A+1,B] )
根據(jù)容斥原理,記 4、100、400 的倍數(shù)的個數(shù)分別為?c1,c2,c3c1,c2,c3
我們有:?n=c1?c2+c3n=c1?c2+c3
根據(jù)?前綴和?的思想,我們有:
c1=(B?1)/4?(A?1)/4c1=(B?1)/4?(A?1)/4
應(yīng)該不會有人看不懂前綴和吧,不過我還是解釋一下吧。
因為 A 是包含在區(qū)間里面的,我們要求 [A,B-1] 的區(qū)間權(quán)值,自然不能把 A 刪出去,所以要用 A-1 。
其它幾項同理。
于是我們求出了閏年的個數(shù),于是?d=(B?A)+n×1d=(B?A)+n×1
至于 A > B 的情形,同理,只需要把區(qū)間改為 [B,A-1] 。
然后根據(jù)前綴和,你會發(fā)現(xiàn)?式子是一樣的,只是正負號變了而已,所以沒有分類討論的必要?。
這樣就解決了最關(guān)鍵的問題,剩下的只需要動用知識和?耐心?去模擬就好了。
問題2 月歷的格式
這個隨便百度一下萬年歷或者點一下右下角的時間模仿一下它的格式就行了。這里介紹幾個技巧。
分行 printf (這個好像誰都會)

對齊
利用?%-*d?可以靠左對齊,?%*d?則是靠右對齊。
總之計算好需要的字符長度然后分配即可??粗恍卸嘣噹状巍?/p>
利用字符數(shù)組減少工作量

需要注意的是,二維數(shù)組的字符串長度必須聲明。因為只有知道了長度才可以分配內(nèi)存。二維數(shù)組不止要分配第一個字符串的內(nèi)存,還要同時按間隔分配余下的內(nèi)存,不規(guī)定長度的話它不知道要在哪里放第二個。
問題3 <time.h>的簡單用法
需要注意的是?tm_year 返回的是差值,且 tm_mon 是從 0 開始的
直接放代碼和注釋。

問題4 美化
基于我對 cmd 界面的認識,我認為改動顏色可以使他更好看!
效果圖

源碼分享:









那么今天的文章就分享到這里了,希望對大家能夠有幫助呀!
另外如果你想更好的提升你的編程能力,學(xué)好C語言C++編程!彎道超車,快人一步!
分享(源碼、項目實戰(zhàn)視頻、項目筆記,基礎(chǔ)入門教程)

學(xué)習(xí)C/C++編程知識,提升C/C++編程能力,歡迎關(guān)注UP一起來成長!
另外,UP在主頁上傳了一些學(xué)習(xí)C/C++編程的視頻教程,有興趣或者正在學(xué)習(xí)的小伙伴一定要去看一看哦!會對你有幫助的~
編程學(xué)習(xí)書籍分享:

編程學(xué)習(xí)視頻分享:
