上一篇中我們用項(xiàng)目思維把我們的程序做了大的調(diào)整,收到的大部分反饋郵件都說(shuō)基本能看懂。今天我們來(lái)實(shí)現(xiàn)最后一部分功能。
今天的程序修改都是在上一篇的基礎(chǔ)上進(jìn)行,請(qǐng)先打開(kāi)之前的項(xiàng)目。
1. 功能函數(shù)封裝
首先要說(shuō)的是main.c這個(gè)文件。在這個(gè)文件的前半部分是一些功能函數(shù),從邏輯上講,這些函數(shù)和主程序的關(guān)系并不是非常密切。如果是一個(gè)很大的工程,就會(huì)出現(xiàn)在很多其他文件中多次調(diào)用這些函數(shù)的情況。試想,如果我們?cè)贛onth.c和String.c中也需要調(diào)用GetMonthStr這個(gè)函數(shù),是不是訪問(wèn)不到呢?請(qǐng)大家先自己試驗(yàn)一下。
為了解決這種問(wèn)題,我們把這幾個(gè)函數(shù)獨(dú)立出來(lái)成為一組新的文件。
-
Function.h
#ifndef __FUNCTION_H__ #define __FUNCTION_H__ char* GetMonthStr(int month); int IsLeapYear(int year); int GetWeek(int year); int GetDays(int year, int month); #endif -
Function.c
#include "Function.h" char g_month[12][10] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; int g_days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; // 通過(guò)月份數(shù)字打印月份名稱(chēng) char* GetMonthStr(int month) { return g_month[month - 1]; } // 判斷閏年,是閏年返回1,是平年返回0 int IsLeapYear(int year) { if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) return 1; else return 0; } // 返回輸入年份的1月1日是周幾 int GetWeek(int year) { return (35 + year + year / 4 - year / 100 + year / 400) % 7; } // 返回輸入的年份中輸入的月份天數(shù) int GetDays(int year, int month) { if (month == 2 && IsLeapYear(year)) { return g_days[month - 1] + 1; } else { return g_days[month - 1]; } }
此時(shí)的main.c文件中只有一個(gè)全局變量g_Month[12]和一個(gè)main函數(shù)了。當(dāng)然,別忘了在前面添加對(duì)Function.h的引用。
#include "Function.h"
2. 并排打印兩個(gè)月份
在Month.c中,我們通過(guò)PrintMonth這個(gè)函數(shù)打印每個(gè)月的日歷。如果我們需要一次并排打印兩個(gè)月份,那么需要在Month.c中添加一個(gè)新的函數(shù)。代碼如下:
// 并排打印兩個(gè)月的日歷
void PrintTwoMonth(Month* pMonthLeft, Month* pMonthRight)
{
int i;
printf("%27s\t", GetMonthName(pMonthLeft));
printf("%27s\n", GetMonthName(pMonthRight));
printf("----------------------------\t----------------------------\n");
printf("Sun Mon Tue Wed Thu Fri Sat\tSun Mon Tue Wed Thu Fri Sat\n");
for (i = 0; i < 6; i++)
{
printf("%27s\t", pMonthLeft->_arrayDays[i].buf);
printf("%27s\n", pMonthRight->_arrayDays[i].buf);
}
}
這個(gè)函數(shù)非常簡(jiǎn)單,每次調(diào)用時(shí)傳入兩個(gè)月份的指針,之后每行前半部分打印左邊一個(gè)月的信息,后半部分打印右邊一個(gè)月的信息。
不要忘了在Month.h中添加這個(gè)函數(shù)的生命,否則main函數(shù)中無(wú)法調(diào)用。
接下來(lái),在main函數(shù)中,我們注釋掉之前的函數(shù)調(diào)用,加上PrintTwoMonth的調(diào)用即可。修改部分如下:
// 打印12個(gè)月的日歷
for (i = 0; i < 12; i++)
{
//PrintMonth(&g_Month[i]);
PrintTwoMonth(&g_Month[i++], &g_Month[i]);
printf("\n");
}
讓我們來(lái)看看運(yùn)行結(jié)果:

這時(shí)候大家就看到我們上一篇所做工作的好處了,程序框架基本不用變化。輕松添加新功能。
2.1 并排打印三個(gè)月份
如果我們需要打印成四行三列的日歷,該怎么辦呢?我們同樣只需要添加一個(gè)打印函數(shù)就可以了。在Month.c中添加函數(shù)如下:
// 并排打印三個(gè)月的日歷
void PrintThreeMonth(Month* pMonthLeft, Month* pMonthMid, Month* pMonthRight)
{
int i;
printf("%27s\t", GetMonthName(pMonthLeft));
printf("%27s\t", GetMonthName(pMonthMid));
printf("%27s\n", GetMonthName(pMonthRight));
printf("----------------------------\t----------------------------\t----------------------------\n");
printf("Sun Mon Tue Wed Thu Fri Sat\tSun Mon Tue Wed Thu Fri Sat\tSun Mon Tue Wed Thu Fri Sat\n");
for (i = 0; i < 6; i++)
{
printf("%27s\t", pMonthLeft->_arrayDays[i].buf);
printf("%27s\t", pMonthMid->_arrayDays[i].buf);
printf("%27s\n", pMonthRight->_arrayDays[i].buf);
}
}
之后在Main函數(shù)中修改調(diào)用即可:
// 打印12個(gè)月的日歷
for (i = 0; i < 12; i++)
{
//PrintMonth(&g_Month[i]);
//PrintTwoMonth(&g_Month[i++], &g_Month[i]);
PrintThreeMonth(&g_Month[i++], &g_Month[i++], &g_Month[i]);
printf("\n");
}
這里需要注意的是,雖然代碼實(shí)現(xiàn)沒(méi)有問(wèn)題,但是命令行程序每行打印字符數(shù)是有限制的。打印三列會(huì)超出寬度限制,導(dǎo)致自動(dòng)折行打亂排版順序。大家可以自己試試。
2.2 代碼共享
如需完整的工程代碼,請(qǐng)?jiān)L問(wèn)GitHub中的代碼文件。
我是天花板,讓我們一起在軟件開(kāi)發(fā)中自我迭代。
如有任何問(wèn)題,歡迎與我聯(lián)系。
上一篇:21天C語(yǔ)言代碼訓(xùn)練營(yíng)(第八天)
下一篇:21天C語(yǔ)言代碼訓(xùn)練營(yíng)(第十天)