速學結構與自訂資料型態

在C++程式設計中,我們往往需要同時處理多種型態不同的資料,以表示複雜的物件或事物。例如學生記錄中除了有學號(整數)、姓名(字串)外,還可能有成績(整數或浮點數)、性別(字元或列舉)與電話號碼(字串)等資料。這時,單純使用陣列或基本變數會使程式碼顯得零散、缺乏結構化;幸運的是,C++提供了可以自行定義的結構型態(struct)、列舉(enum)、聯合(union)與型態定義(typedef)等自訂資料型態工具。這些機制讓程式設計師可創造出更具彈性與可讀性的型態,使程式碼更容易理解、維護與擴展。


8-1 結構 (struct) 簡介

結構的概念:
結構(struct)是一種集合多種不同型態資料的複合資料型態。透過結構,程式設計師能將相關的資料彙整為一個整體,輕鬆地對整體物件進行操作,而不必分散管理每一個成員。換句話說,結構就是用來表示實際問題中複雜資料的一種手段,好比一本「資料表單」:每個成員表示不同的欄位欄位,而整個結構物件就是一筆完整的紀錄。

這種自訂型態特別適合表達較複雜的實體,如學生檔案(包含姓名、學號、成績)、公司員工資料(包含員工代號、名字、薪資、職稱)或一個3D點座標(包含x、y、z三個維度的值)。


8-1-1 宣告結構變數

結構定義語法:

 
cpp
struct 結構名稱 { 資料型態 成員1; 資料型態 成員2; // ... 可包含多種不同資料型態的成員 }; //別忘了最後的分號!

定義結構並不會直接配置記憶體空間,而是告訴編譯器產生一種新的型態定義。要使用結構,必須宣告結構變數:

 
cpp
struct 結構名稱 變數1, 變數2, ...;

舉例:

 
cpp
struct student { char name[10]; int score; int ID; }; struct student s1, s2; // 宣告兩個 student 型態的變數

若要同時定義結構並宣告變數,可將變數宣告放在結構定義的尾端,例如:

 
cpp
struct student { char name[10]; int score; int ID; } s1, s2;

存取結構成員:
透過「點號」(dot operator)運算子來存取結構成員:

 
cpp
s1.score = 90; cin >> s1.name;

結構變數的指定運算也相當便利,可直接將一個結構變數指定給另一個相同型態的結構變數,而不必逐一指定成員:

 
cpp
s2 = s1; // 將 s1 的內容整體複製到 s2

結構陣列:
若要存放多筆相同型態的結構資料,可宣告結構陣列:

 
cpp
struct student class1[5]; // class1 是五個student型態的陣列

透過結構陣列,我們可輕鬆遍歷所有紀錄:

 
cpp
for (int i=0; i<5; i++) { cout << class1[i].name << " " << class1[i].score << endl; }

巢狀結構:
結構的成員不僅可以是基本型態或陣列,也可以是另一個結構,形成「巢狀結構」。透過巢狀結構,我們可描述更複雜的資料。例如:

 
cpp
struct address { char city[20]; char street[20]; int number; }; struct person { char name[10]; address home; }; person p; cin >> p.name >> p.home.city >> p.home.street >> p.home.number;

每層結構多一層點號存取。例如:p.home.city可取得該人的所在城市名稱。


8-2 列舉 (enum)

列舉型態的概念:
列舉是一種能將一組相關常數定義為列舉成員的型態,透過具意義的名稱代替神祕的數值常數,使程式碼的可讀性與維護性提升。列舉成員預設從0開始遞增,但也可自行指定初始值。

列舉宣告語法:

 
cpp
enum 列舉型態名稱 { 列舉成員1, 列舉成員2, ... };

範例:

 
cpp
enum Drink { coffee = 25, milk = 20, tea = 15, water // 沒有指定值,則從上一個值後依序+1,即 water=16 }; enum Drink c_drink; c_drink = coffee; // c_drink為25 c_drink = water; // c_drink為16

透過列舉,我們能清楚地使用coffeemilkteawater這些名字,替代模糊不清的數字常數,大幅提升程式碼語意明確度。


8-3 聯合型態 (union)

聯合的概念:
聯合(union)和結構很像,都能集合多種不同型態的成員,但最大差異在於聯合的所有成員「共用同一塊記憶體區域」。也就是說,聯合變數會以成員中「所需空間最大者」來配置記憶體大小,其餘成員共用這塊空間。

這意味著在同一時間,只有一個成員能有意義的值,其餘成員若被存取則會出現不預期的結果。

聯合宣告語法:

 
cpp
union 名稱 { 資料型態 成員1; 資料型態 成員2; ... };

範例:

 
cpp
union Data { int i; char c[4]; }; Data d; d.i = 1234;

由於i與c共用空間,因此若讀取d.c[0]d.c[1]等,將會是該整數的位元組表示。

應用情境:
聯合常用於需在同一記憶體空間中存放不同型態資料的場景。例如程式中加解密或解析資料包,不同時間以不同格式詮釋該區域記憶體的內容。這樣可節省記憶體使用量,不過必須清楚了解聯合的限制。


8-4 型態定義 (typedef)

typedef的功能:
typedef指令可用來為現有資料型態(包括基本型態、結構、陣列等)重新定義一個更直覺或方便使用的名稱。透過typedef,我們可使程式碼更易讀、易管理,特別當原先型態名稱冗長或難記時。

 
cpp
typedef int INTEGER; // INTEGER現在代表int typedef char STRING[20];// STRING現在代表長度20的字元陣列 INTEGER x = 10; // x即為 int x = 10; STRING name; // name是長度20的char陣列

結合struct與typedef:
若經常使用某個結構型態,可用typedef將struct省略:

 
cpp
typedef struct { int roomNumber; char houseName[10]; } house_info; house_info myhouse; // 直接使用house_info宣告,不必每次寫struct

常見錯誤與問題分析

  1. 結構定義後漏掉分號:

     
    cpp
    struct student { char name[10]; int score; } // ←漏掉分號

    一定要在結構定義結束的}後加上分號!

  2. 結構型態重複定義相同名稱的結構:
    在同一作用域(同一檔案內)定義同名結構會造成編譯錯誤,必須使用不同名稱或將其擺在不同namespace或檔案。

  3. 使用typedef後仍加上struct關鍵字:

     
    cpp
    typedef struct house { int roomNumber; char houseName[10]; } house_Info; struct house_Info myhouse; // 不必加struct,可直接使用house_Info myhouse;

    修正後:

     
    cpp
    house_Info myhouse;
  4. 使用enum時不當使用:
    在enum中成員名稱若有重複、或是將列舉值指定給不適合的變數型態,可能造成編譯錯誤或程式語意不清。確保每個列舉成員都具備清晰的語意。

  5. 聯合型態中成員共用記憶體造成混淆:
    若你在union中已經透過某成員寫入資料後,又透過另一成員讀取,可能產生不可預期結果。請確保在同一時刻只針對其中一個成員有意義的存取。


課後評量與深入思考

  • 指出以下程式碼的錯誤:

     
    cpp
    typedef struct house { int roomNumber; char houseName[10]; } house_Info; struct house_Info myhouse;

    此處多餘的struct關鍵字可移除。

  • 若有一個enum Drink定義:

     
    cpp
    enum Drink { coffee=25, milk=20, tea=15, water };

    請問water的值為多少?
    coffee=25, milk=20, tea=15, water未指定則延續最後一次指定值,tea為15,water自15加1=16。

  • 解釋為何二元搜尋法(binary search)須先確保資料排序後才能使用?
    雖然此為前章所述的演算法題材,但可引申思考:自訂型態(如struct)的成員若是鍵值,排序有助於後續以列舉或switch-case進行邏輯判斷或搜尋。


總結

在本章中,我們介紹了C++中4種自訂資料型態:結構(struct)、列舉(enum)、聯合(union)與型態定義(typedef)。透過這些工具,我們不僅可輕鬆表示複雜的實體或資料集,也能為原有資料型態重新命名,使程式碼更具可讀性與彈性。

  • 結構能群組不同型態的資料成員,形成一個有意義的自訂型態。
  • 列舉將常數命名化,使程式碼更清晰易讀。
  • 聯合雖可共用記憶體空間,但使用時須格外謹慎,避免成員間衝突。
  • typedef可為現有型態取更佳的名稱,提升程式碼易讀度。

掌握這些自訂資料型態,不僅是在C++程式設計中必備的基礎,更是在面對複雜問題時的重要工具,使我們能夠在日後更進階的程式設計任務中靈活運用、優雅解決問題。

創作者介紹
創作者 AI革命家 REVOLUTIONARY 的頭像
AI革命家

AI革命家 REVOLUTIONARY

AI革命家 發表在 痞客邦 留言(0) 人氣( 6 )