/* 1. 定義結構體型別 (標籤為 Student) */
struct Student {
char name[20];
char sex;
long id;
float scores[3];
};
/* 2. 使用型別宣告變數 */
struct Student stu1, stu2; // 兩個變數
struct Student classA[50]; // 陣列
struct Student *ptr = &stu1; // 指標
優點:型別可複用、可建立任意數量變數、程式碼清晰、支援前向宣告。
struct Date {
int day;
int month;
int year;
} today, tomorrow; // 直接宣告兩個變數
/* 後續仍可用型別繼續宣告 */
struct Date birthday, deadline;
適用:一次性腳本、極少複用的小型程式。
struct {
char name[20];
char sex;
long id;
float scores[3];
} person1, person2; // 只有這兩個變數,無法再宣告第三個
缺點:無型別名稱,**無法**在別處宣告同結構變數、無法作為函數參數型別、無法建立指向該型別的指標 (需用 `void*` 或 GCC 延伸 `__typeof__`)。
| 特性 | 方式一 (標籤型別) | 方式二 (同時宣告) | 方式三 (匿名) |
|---|---|---|---|
| 型別可複用 | ✅ 是 | ✅ 是 | ❌ 否 |
| 可作函數參數型別 | ✅ 是 | ✅ 是 | ❌ 否 |
| 可建立指標型別 | ✅ `struct Student*` | ✅ `struct Date*` | ❌ 無型別名 |
| 前向宣告支援 | ✅ `struct Student;` | ✅ 同上 | ❌ 不可能 |
| 典型用途 | **通用資料結構** | 一次性資料群組 | 極局部、一次性 |
/* 定義同時建立別名 */
typedef struct Student {
char name[20];
int age;
} Student; // 現在可直接用 Student (無需 struct 關鍵字)
Student s1; // 簡潔
Student *ps = &s1; // 指標也簡潔
注意:C 語言結構體標籤空間與普通識別碼空間分離,`struct Student` 與 `typedef Student` 可同名不衝突。
struct A { char c; int i; double d; }; // 1 + 3pad + 4 + 4pad + 8 = 24
struct B { double d; int i; char c; }; // 8 + 4 + 1 + 3pad = 16
**成員排序影響大小**:按**遞減對齊需求**排列 (大型別在前) 可減少填充。
struct Node { int val; struct Node *next; };
/* 箭頭運算子等價於 (*ptr).member */
ptr->val = 10; // 等同 (*ptr).val = 10
ptr->next = malloc(sizeof(struct Node));
| 錯誤 | 修正 |
|---|---|
| `struct { int a; } x; struct y = x;` (匿名型別無法轉換) | 改用方式一或二,有具名型別 |
| 忘記結構體定義結尾分號 `}` | 務必加 `};` |
| 柔性陣列成員不在結尾 | 柔性陣列 (C99) 必須是**最後一個成員** |
| 位元欄位跨越儲存單元 | 單一位元欄位不可超過底層型別位寬 |
**方式一 (具名標籤 + 後續宣告)** 是工程級代碼的標準選擇,配合 `typedef` 簡化名稱。方式三僅限極局部、一次性資料封裝。理解三種方式的**型別複用能力差異**,能避免「無法在別處宣告同結構變數」等低級錯誤。