---
# System prepended metadata

title: Untitled

---

## 結構 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
```