前言
結構體 (struct) 是 C/C++ 自訂複合資料類型的基石。它能聚合異質資料、支援整體指派、配合指標實現動態資料結構。本文涵蓋定義語法、記憶體模型、指標操作、與類別的關鍵差異。
一、定義與實例化
// 定義結構體類型
struct Student {
int id;
char name[32];
float gpa;
};
// 宣告變數 (C++ 可省略 struct 關鍵字)
Student s1; // 預設初始化 (成員未初始化)
Student s2 = {1001, "Alice", 3.8}; // 聚合初始化 (C++20 指定初始化: .id=1001)
Student s3 = s2; // 整體複製 (逐成員複製)
二、成員存取
| 語法 | 適用對象 | 範例 |
. (點運算子) | 結構體變數/參考 | s1.id = 1002; |
-> (箭頭運算子) | 結構體指標 | Student* p = &s1; p->gpa = 4.0; |
三、記憶體佈局與對齊
struct AlignDemo {
char c; // offset 0, size 1
// 3 bytes padding
int i; // offset 4, size 4 (4-byte aligned)
double d; // offset 8, size 8 (8-byte aligned)
}; // sizeof = 24 (含尾部 padding 確保陣列對齊)
- 成員依宣告順序配置,位址遞增
- 每個成員按其對齊需求對齊 (通常等於大小)
- 結構體整體對齊 = 最大成員對齊
#pragma pack(n) 或 `__attribute__((packed))` 可壓縮佈局 (效能/相容性權衡)
四、結構體指標與動態配置
// 動態配置單一實例
Student* p = new Student{1002, "Bob", 3.5};
p->id = 1003;
delete p;
// 動態陣列
Student* arr = new Student[100];
arr[50].gpa = 3.9;
delete[] arr;
// C 風格
Student* p = (Student*)malloc(sizeof(Student));
// ... 使用
free(p);
五、整體指派與比較
Student a = {1, "A", 3.0};
Student b = a; // 合法:逐成員複製
// Student c; c = a; // 合法
// 比較:無內建 operator==,需自行實作或逐成員比較
bool equal = (a.id == b.id) && (strcmp(a.name, b.name) == 0) && (a.gpa == b.gpa);
關鍵差異:陣列名為常數指標,不可作為左值指派 (`arr1 = arr2` 錯誤);結構體變數可直接指派。
六、C 與 C++ 結構體差異
| 特性 | C (ISO C99) | C++ (ISO C++11+) |
| 標籤命名空間 | 獨立 (`struct Student`) | 共用 (`Student` 直接可用) |
| 成員函數 | 不支援 | 支援 (方法、建構子、運算子) |
| 存取控制 | 無 (全 public) | public/protected/private |
| 預設存取 | N/A | public (struct) / private (class) |
| 建構子/解構子 | 無 | 支援 (RAII) |
| 繼承 | 無 | 支援 |
| 靜態成員 | 無 | 支援 |
七、進階用法
位欄位
struct Flags {
unsigned int isActive : 1;
unsigned int priority : 3; // 0-7
unsigned int reserved : 28;
}; // 共 4 bytes
柔性陣列成員 (C99/C++11 條件支援)
struct Buffer {
size_t len;
char data[]; // 最後一個成員,大小由配置時決定
};
Buffer* buf = (Buffer*)malloc(sizeof(Buffer) + 1024);
buf->len = 1024;
匿名結構體/聯集 (C11/C++11 擴充)
struct Outer {
int x;
struct { int y, z; }; // 匿名內部結構
};
Outer o; o.y = 10; // 直接存取
八、常見錯誤與最佳實踐
| 錯誤 | 正確做法 |
| 結構體定義末尾漏分號 | 養成 `};` 習慣 |
| 未初始化即使用成員 | 提供預設建構子、聚合初始化、或 `{0}` 零初始化 |
| 指標解參考前未檢查 nullptr | `if (p) p->member;` |
| 跨編譯單元共用結構體定義不一致 | 放入共用標頭檔,防衛性 `#pragma once` |
| 假設記憶體佈局固定 (序列化/網路傳輸) | 使用標準序列化 (protobuf, JSON) 或手動打包 |
結語
結構體是 C/C++ 資料建模的核心。掌握其記憶體佈局、指標操作、整體指派語意,並理解 C/C++ 差異,能設計高效、可維護的資料結構。現代 C++ 傾向使用 class 封裝行為、struct 表達純資料聚合 (POD-like),配合 RAII 與標準庫容器,構建強健系統。