## 結構 structure [toc] ### Intro - 如果我們有一些相關的資料,但是其資料類別不一致,我們就可以使用**結構(structure)** 來將這些資料搜集再一起。 - 而一個結構中有許多**欄位(field)**,就如同一個陣列有許多元素一樣。 :::info :bulb: 陣列用來存很多相同類別的資料、結構用來存很多不同類別的資料。 ::: ### 定義 - structure是一種**derived data type(衍生數據類型)**,考慮以下的structure定義: ```c #define NAMELEN 20 #define PHONELEN 10 #define YEAR 4 struct student{ char name[NAMELEN]; int id; char phone[PHONELEN]; float grade[YEAR]; int birth_year, birth_month, birth_day; }; ``` - keyword `struct` + structure tag(自己定義的資料類型的名稱,如: student) - 記得在最後面的大括號後加上分號 #### 宣告類別 如果要宣告一個student類型的變數,如: ```c struct student john; ``` - 我們可以將struct student看成一個資料類別。 :::info :bulb:C++中,宣告不同的structure類型變數時不需要加上struct這個keyword ::: 另外也可以這樣宣告:(直接加在structure的定義後) ```c struct student{ char name[NAMELEN]; int id; char phone[PHONELEN]; float grade[YEAR]; int birth_year, birth_month, birth_day; }john; ``` :::info :bulb:值得注意的是,structure沒有"="運算子,因為structure中的不同變數會存在記憶體中不連續的位址 ::: #### 結構大小 計算`struct student`的位元大小: $\text{sizeof}(\text{struct student})\\ \quad =30\times\text{sizeof}(\text{char})+4\times\text{sizeof}(\text{int})+4\times\text{sizeof}(\text{float})\\ \quad =30\times 1+4\times4+4\times4\\ \quad=30+16+16\\ \quad=62$ 但實際上,`struct student`的位元大小是64,在等等會提到為何會差2。 ### 初始化 跟初始化陣列的方法很像,在大括號中、用逗點把不同的初始值分隔開來,如: ```c struct student john = {"John Smith", 12345, "1234567", {4.0,3.9,3.8,3.6}, 2000, 1, 1}; ``` 另外也可以一個個變數去初始化,如: ```c john.id = 12345; john.birth_year = 2000; strcpy(john.name,"John Smith"); ``` :::info :bulb:除了在宣告時初始化外,也能用=與strcpy等方式設定。 ::: ### 欄位 #### 存取 會需要兩種運算子: - `.`(structure member operator) - `->`(structure pointer operator or arrow pointer) 主要的差別在:`.`是用在一般的struct變數、而`->`是用在指向struct的指標,如: ```c printf("%s",aCard.suit); printf("%s",cardPtr->suit);//equivant to (*cardPtr).suit; ``` #### 記憶體位址 - 各欄位的記憶體位址順序按照宣告順序 - 因為浮點數的記憶體位址必須是四的倍數,因此雖然只需要10位元,實際上還是會開到12,稱為**對齊(alignment)** ::: info :bulb:結構內各欄位都是按照宣告順序一一出現在記憶體中,但中間可能會有因為資料型態不同而需要對其產生的空隙。 ::: ### Using Structure with Functions - structure member:pass by value(copy一份傳到函式中) - structure variable:pass by value(copy一份傳到函式中) - structure pointer:pass by reference(直接修改原本的值) ### typedef 如果覺得要宣告一個structure類型的變數很麻煩,可以用typedef來縮短: ```c typedef struct{ char name[NAMELEN]; int id; char phone[PHONELEN]; float grade[YEAR]; int birth_year, birth_month, birth_day; }Student; ``` 因此下次宣告變數時只要: ```c Student john;//宣告一個Card類型的變數card ```