21天C語(yǔ)言代碼訓(xùn)練營(yíng)(第九天)

上一篇中我們用項(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)(第十天)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 第1章 第一個(gè)C程序第2章 C語(yǔ)言基礎(chǔ)第3章 變量和數(shù)據(jù)類(lèi)型第4章 順序結(jié)構(gòu)程序設(shè)計(jì)第5章 條件結(jié)構(gòu)程序設(shè)計(jì)第6章...
    小獅子365閱讀 10,892評(píng)論 3 71
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類(lèi)相關(guān)的語(yǔ)法,內(nèi)部類(lèi)的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚(yú)_t_閱讀 34,854評(píng)論 18 399
  • 繼續(xù)我們之前的項(xiàng)目,上一篇中我們完成了自己的String類(lèi)型設(shè)計(jì),封裝了相關(guān)的功能。有朋友留言中提到C語(yǔ)言中有相應(yīng)...
    天花板閱讀 4,158評(píng)論 8 52
  • 今天開(kāi)始看《W兩個(gè)世界》,劇情跌宕起伏,完全沉溺其中。加上在旅途中,完全處于斷網(wǎng)狀態(tài),能安安心心看一部劇的時(shí)候不多...
    茉莉大大閱讀 290評(píng)論 0 0
  • 放手,放手,放手。她想過(guò)無(wú)數(shù)次,但總是無(wú)法跨出那一步…… 三年前的今天,不同世界的兩個(gè)陌生人也不知因...
    月亮后的小姑娘閱讀 214評(píng)論 0 0

友情鏈接更多精彩內(nèi)容