進階資料型別


  1. Structures (結構)
    1. 結構定義的語法: 請參考 stack.ccomplex.c
    2. 如果把資料庫中的一個表格想成是 C 語言中的一個結構陣列, 那麼:
                      建立表格        就是    定義結構
                      一筆記錄        就是    陣列的一個元素
                      表格的一個欄位  就是    結構的一個欄位
              
      

    3. 所以說, 定義一個結構型時, 別並未向系統要空間來使用, 例如 typedef struct complex { ... } complex; 只有在定義新的結構變數時, 才是真的向系統要空間來用, 例如 complex z, sz, t;
    4. 存取結構變數中的一個欄位: 如果有 complex * p;p->re(*p).re 效果完全相同, 代表 "p 所指到的結構變數的 re 欄位".
    5. 宣告/定義變數時同時設定起始值: 語法類似陣列設定起始值.
    6. 結構變數可以整個拷貝 (用 "=", 或傳遞參數, 或函數傳回值), 但是不可以整個做比較用 ("==" 與 "!=" 都不可以). 為什麼? C 編譯器不知道在你的心目中何謂兩個結構相等. 例: 有理數的相等未必要分子相等而且分母相等.
    7. 良好的結構設計及欄位命名原則 (參考 school.c):
      1. 避免重複: 資料盡量不要重複儲存, 以免產生 data integrity 的漏洞
        1. 避免不同的記錄之間的資料重複: 如果你在設計的是資料庫表格而這一欄位你會用外鍵的話, 在 struct 定義中可能就應該要用 pointer.
        2. 避免同一個記錄內的資料重複: 可以推算出來的衍生資料盡量不要儲存, 改用函數
      2. 萃取共同欄位: 如果發現一群欄位重複在幾種不同的記錄定義中出現, 或許該定義子記錄.
      3. 程式閱讀順口: 欄位名稱要能凸顯在該紀錄中所扮演的角色, 而不要按照型別的名稱命名.
      4. 節省參數: 副程式參數盡量使用結構, 且不要向呼叫者要不需要的資訊.
    8. 作業: 讀入成績檔 (每列包含姓名, 學號, 及德智體群四個成績), 使用你最熟悉的演算法把所有資料按照體育成績由低而高排序並印出.
    9. 作業: 模倣 UNIX 指令 cal. 注意: 1752 年 9 月的月曆是:
                         September 1752
                      Su Mo Tu We Th Fr Sa 
                             1  2 14 15 16
                      17 18 19 20 21 22 23
                      24 25 26 27 28 29 30
              
      

      而之前的月曆只有簡單的「四年一閏」規則. 可參考 date.c
    10. 作業: (傳指標給副程式的練習) 把 complex.cdate.c 改寫成所有結構參數都是以指標傳遞. 答案可從本頁的本文檔找到.
  2. Emumeration
    1. 算是一種助憶名稱 (mnemonics), 省去程式中以數字代號表示的不便. 例:
                      typedef enum {
                          SPADE, HEART, DIOMAND, CLUB
                      } suit_type;
                      typedef struct {
                          suit_type suit;
                          int pip;
                      } card;
      
                      card hand[5] = {                /* 一手牌有五張 */
                          { SPADE, 5 }, { HEART, 10 }, { SPADE, 7 },
                          { DIOMAND, 13 }, { SPADE, 12 }
                      };
              
      

    2. 和整數形態相容
  3. Union: 為節省空間, 讓數種相關但不同的資料共享同一塊記憶體空間. 現在除了要存檔時偶爾會用到以外, 平常已很少使用.
  4. Packed structure: 為節省空間, 讓結構的欄位以 bit 為單位分配使用空間. 現在除了與硬體溝通的低階程式以外, 平常已很少使用.
  5. 指到函數的指標變數 (此觀念與 C++ 中的 virtual function 相關). 也請參考 把函數當做資料來用. 例一: 學會使用內建函數 qsort.
    1. 讀入成績檔 (每列包含姓名, 學號, 及德智體群四個成績), 根據命令列參數決定要按照那一個欄位排序印出. 使用 qsort().
    2. 改進上述程式, 讓 qsort 只移動指標, 不移動結構本身, 以節省時間.
    3. 以梯形法對任意的單變數實數函數作數值積分.
    4. 寫一個副程式 do_all_files 對指定目錄底下 (遞迴入子目錄), 所有檔案名稱中包含某一指定字串的檔案, 作指定的動作. 例如: do_all_files("/usr/include", "std", print_file);do_all_files("c:\\tmp", "bak", delete_file);
  6. 指到函數的指標變數例二: function dispatch table 請與 sitio.c 的主程式對照. 兩者都包含 (include) 了 sitio.h. 題外話: DOS 與 MS Windows 的使用者必須在 config.sys 當中加上 device = ansi.sys 一句. (可用系統內建版本, 或下載 nansi.)