結構體核心知識體系
三種定義方式
/**** 1. 僅定義類型 ****/
struct Stuff {
char job[20];
int age;
float height;
};
/**** 2. 定義同時聲明變量 ****/
struct Stuff {
char job[20];
int age;
float height;
} Huqinwei; // 等價於 struct Stuff Huqinwei;
/**** 3. 匿名結構體(僅用一次) ****/
struct {
char job[20];
int age;
float height;
} Huqinwei;
初始化與賦值
/**** 初始化 ****/
struct Stuff Huqinwei = {"manager", 30, 185.0};
/**** 結構體賦值(整體拷貝) ****/
struct Stuff faker = Huqinwei; // 或 faker2 = faker;
/**** 成員逐個賦值 ****/
Huqinwei.job[0] = 'M'; // 字符數組需逐字符或用 strcpy
strcpy(Huqinwei.job, "engineer");
Huqinwei.age = 27;
指針操作
struct Stuff *ptr = &Huqinwei;
ptr->age = 100; // 等價於 (*ptr).age = 100
printf("%d\n", Huqinwei.age); // 100
結構體數組
struct Test { int a[3]; int b; };
struct Test student[3] = {
{{66,77,55}, 0},
{{44,65,33}, 0},
{{46,99,77}, 0}
}; // 可簡化為 {{66,77,55,0}, ...}
結構體嵌套
struct A {
struct B { int c; } b; // 定義並聲明成員 b
struct B sb; // 再次聲明同類型成員
} a;
a.b.c = 11;
a.sb.c = 22;
結構體與函數
| 傳遞方式 | 代碼示例 | 特點 |
| 值傳遞 | void func(struct A a) | 拷貝整個結構體,開銷大 |
| 指針傳遞 | void func(struct A *a) | 傳遞地址,可修改原值 |
| 成員傳遞 | func(a.b.c) | 僅傳遞單一成員,如基本類型 |
內存佈局與對齊
struct Stuff { char job[20]; int age; float height; };
printf("%zu\n", sizeof(struct Stuff)); // 28 (20+4+4,無填充)
printf("%zu\n", sizeof(Huqinwei)); // 28
- 結構體大小 = 成員大小之和 + 填充字節
- 首地址對齊:成員偏移量為其類型大小的整數倍
- 整體大小為最大成員大小的整數倍
- 不允許在定義時初始化成員(C++ 允許)
柔性數組成員(C99)
struct Flexible {
int len;
char data[]; // 末尾柔性數組
};
struct Flexible *p = malloc(sizeof(struct Flexible) + 100);
p->len = 100; strcpy(p->data, "variable data");
常見錯誤
- 返回棧上結構體指針:
struct A* f() { struct A a; return &a; } → 未定義行為
- 結構體比較:
if (a == b) 不合法,需逐成員比較或 memcmp
- 位域跨邊界:
int a:3, b:5; 可能跨字節,移植性差