結構體是 C 語言構建複雜數據類型的基石,允許將不同類型的數據組合成一個邏輯整體。本文系統講解結構體的定義方式、數組應用、指針操作、函數傳參語義、嵌套定義及枚舉類型。
// 方式1:分離定義類型與變量(推薦,可復用類型)
struct Student {
int age;
};
struct Student stu;
// 方式2:定義類型同時定義變量
struct Student {
int age;
} stu;
struct Student stu2; // 可繼續使用類型名定義
// 方式3:匿名結構體(無法復用類型名)
struct {
int age;
} stu;
struct Person {
int age;
double height;
char *name;
};
int main() {
// 完全初始化
struct Person p1 = {20, 1.55, "jack"};
// 指定成員初始化(C99),順序可打亂
struct Person p2 = {.height = 1.78, .name = "jim", .age = 30};
// 錯誤:定義後不能用花括號賦值
// struct Person p3; p3 = {30, 1.67, "jake"}; // 編譯錯誤
return 0;
}
struct RankRecord {
int no;
char *name;
int score;
};
int main() {
struct RankRecord records[3] = {
{1, "jack", 5000},
{2, "jim", 500},
{3, "jake", 300}
};
for (int i = 0; i < 3; i++) {
printf("%d\t%s\t%d\n", records[i].no, records[i].name, records[i].score);
}
return 0;
}
struct Student {
int no;
int age;
};
int main() {
struct Student stu = {1, 20};
struct Student *p = &stu;
// 方式1:解引用後用點操作符
(*p).age = 30;
// 方式2:箭頭操作符(推薦,更直觀)
p->age = 30;
p->no = 2;
printf("age=%d, no=%d\n", p->age, p->no);
return 0;
}
這是 C 語言函數調用語義的核心區別:
| 傳遞方式 | 語法 | 內存行為 | 能否修改實參 |
|---|---|---|---|
| 值傳遞 | void test(struct Student s) | 拷貝所有成員到形參,佔用棧空間 | 不能,修改只影響副本 |
| 地址傳遞 | void test(struct Student *p) | 傳遞指針,形參指向實參 | 能,通過 p->member 修改實參 |
#include <stdio.h>
struct Student { int age; int no; };
// 值傳遞:不影響實參
void test_val(struct Student s) { s.age = 30; s.no = 2; }
// 地址傳遞:影響實參
void test_ptr(struct Student *p) { p->age = 15; p->no = 2; }
// 指針傳遞但修改指針指向:不影響實參(指針本身是值傳遞)
void test_ptr_rebind(struct Student *p) {
struct Student stu2 = {15, 2};
p = &stu2; // 只改變局部指針 p 的指向
p->age = 16; // 修改的是 stu2,而非 main 中的 stu
}
int main() {
struct Student stu = {28, 1};
test_val(stu);
printf("值傳遞後: age=%d, no=%d\n", stu.age, stu.no); // 28, 1
test_ptr(&stu);
printf("地址傳遞後: age=%d, no=%d\n", stu.age, stu.no); // 15, 2
test_ptr_rebind(&stu);
printf("重綁指針後: age=%d, no=%d\n", stu.age, stu.no); // 15, 2(未變)
return 0;
}
結構體成員可以是另一個結構體類型,實現層級數據建模:
struct Date {
int year, month, day;
};
struct Student {
int no;
struct Date birthday;
struct Date enrollDate;
};
int main() {
struct Student stu = {1, {2000, 9, 10}, {2012, 9, 10}};
printf("生日: %d-%d-%d\n", stu.birthday.year, stu.birthday.month, stu.birthday.day);
return 0;
}
注意:結構體定義內不能直接嵌套自身類型的變量(會導致無限遞歸大小),但可以嵌套指向自身類型的指針(用於鏈表、樹等結構)。
枚舉本質是整型常量的別名,增強代碼可讀性:
enum Sex { Man, Woman, Unknown }; // 默認 0, 1, 2
enum Season {
Spring = 1, // 指定起始值
Summer, // 2
Autumn, // 3
Winter // 4
};
int main() {
enum Season s = 100000; // C語言弱類型,不報錯,但語義錯誤
printf("%d\n", s); // 輸出 100000
return 0;
}
最佳實踐:配合 switch 使用枚舉,編譯器可提示未處理的情況;避免將枚舉作為任意整數使用。
struct Type *;僅讀取時可用 const struct Type *。switch 實現窮盡性檢查。