系統整理結構體指標的宣告、存取成員、陣列操作、函數參數傳遞差異,附完整範例程式碼。
struct Student {
int id;
char name[32];
float score;
};
struct Student stu = {1001, "Alice", 92.5};
struct Student *p = &stu;
// 存取成員:三種等價寫法
p->id; // 最常用:指標直接存取
(*p).id; // 解引用後存取 (需括號,優先級)
stu.id; // 原變數直接存取
// 修改成員
p->score = 95.0; // 等同 stu.score = 95.0
struct Student class[3] = {
{1001, "Alice", 92.5},
{1002, "Bob", 87.0},
{1003, "Carol", 91.0}
};
struct Student *p = class; // 指向陣列首元素
// 陣列指標運算
p[0] // 第 1 個學生
p[1] // 第 2 個學生
(p+1)->name // 等同 p[1].name
// 遍歷陣列
for (int i = 0; i < 3; i++) {
printf("%d: %s %.1f\n", p[i].id, p[i].name, p[i].score);
}
// 位址運算
// 假設 sizeof(Student) = 40 (含 padding)
// p -> 位址 1000
// p + 1 -> 位址 1040 (下一個元素)
// p + 2 -> 位址 1080
| 運算式 | 結合方向 | 等價寫法 | 結果 |
|---|---|---|---|
| ++p->id | 右→左 | ++(p->id) | p 指向的學生 id +1 |
| (++p)->id | 右→左 | (++p)->id | p 移到下一個,取其 id |
| p++->id | 右→左 | (p++)->id | 取目前 p 的 id,再移 p |
| p->id++ | 右→左 | (p->id)++ | 取 id 後 +1 (後置) |
口訣:->、.、[]、() 最高優先級;++、--、*、& 次之;不確定時加括號。
void modifyByValue(struct Student s) {
s.id = 999;
s.score = 100.0;
printf("函數內: %d %.1f\n", s.id, s.score); // 999 100.0
}
int main() {
struct Student stu = {1001, "Alice", 92.5};
modifyByValue(stu);
printf("主程式: %d %.1f\n", stu.id, stu.score); // 1001 92.5 (未變)
return 0;
}
void modifyByRef(struct Student *p) {
p->id = 999;
p->score = 100.0;
printf("函數內: %d %.1f\n", p->id, p->score); // 999 100.0
}
int main() {
struct Student stu = {1001, "Alice", 92.5};
modifyByRef(&stu);
printf("主程式: %d %.1f\n", stu.id, stu.score); // 999 100.0 (已變)
return 0;
}
| 場景 | 建議 | 理由 |
|---|---|---|
| 小型結構體 (<16 bytes)、唯讀 | 傳值 | 無副作用、編譯器優化佳、執行緒安全 |
| 大型結構體、需修改 | 傳址 | 避免複製開銷、可修改原值 |
| 需修改但想保護原值 | 傳值 + 回傳新值 | 函數式風格、無副作用 |
| API 設計、跨模組 | 傳址 (const) | 介面穩定、語意明確 |
struct Student *ptrs[3]; ptrs[0] = &stu1; ptrs[1] = &stu2; ptrs[2] = &stu3; // 透過指標陣列排序、篩選,不移動大結構體 qsort(ptrs, 3, sizeof(struct Student*), compareByScore);