結構體與聯合體入門
從基礎語法到實際應用 - 掌握資料組織的核心技巧與記憶體管理方法
1. 結構體基礎概念
1.1 為什麼需要結構體?
- 生活案例:
- 單一變數 → 便利貼(只能記一件事)
- 結構體 → 學生證(整合姓名、學號、照片)
- 程式碼對比:
// 舊方法:分散變數 char name[50]; int student_id; float score; // 新方法:結構體整合 struct student { char name[50]; int student_id; float score; };
1.2 定義與初始化
// 定義「座標」結構體
struct point {
int x;
int y;
};
// 初始化方式
struct point p1 = {10, 20}; // 順序初始化
struct point p2 = {.y=30, .x=5}; // 指定成員初始化(C99標準)
struct point p3; // 先宣告後賦值
p3.x = 100; p3.y = 200;
1.3 存取成員
printf("p1座標: (%d, %d)\n", p1.x, p1.y); // 點運算子存取
p1.x += 5; // 修改成員值
2. 結構體指標
2.1 指標基礎回顧
int num = 10;
int *ptr = # // 指向整數的指標
printf("%d", *ptr); // 用*取值
2.2 結構體指標操作
struct student s1 = {"Alice", 410530, 90.5};
struct student *s_ptr = &s1;
// 兩種存取方式對比
printf("Name: %s\n", (*s_ptr).name); // 括號不可省略!
printf("Name: %s\n", s_ptr->name); // 推薦用箭頭運算子
2.3 結構體指標實戰
// 函數參數傳遞結構體指標(避免複製開銷)
void print_student(const struct student *s) {
printf("Student ID: %d\n", s->student_id);
}
int main() {
struct student s1 = {"Bob", 410531, 88.0};
print_student(&s1); // 傳遞地址
return 0;
}
3. 綜合範例
3.1 設計「手機」結構體
struct smartphone {
char model[20];
int ram; // GB
float price;
};
// 1. 宣告兩支手機
// 2. 寫一個函數用指標參數印出手機資訊
void print_phone(const struct smartphone *phone) {
printf("Model: %s\n", phone->model);
// 補完其他資訊打印
}
3.2 想一想
struct book {
char title[50];
int pages;
};
struct book b1 = {"C Programming", 300};
struct book *b_ptr = &b1;
// 提問:以下程式碼輸出什麼?
printf("%d", b_ptr->pages + 10);
Clang編譯小技巧:
clang -Wall -Wextra struct_practice.c # 開啟所有警告
4. 結構體陣列
4.1 靜態結構體陣列
// 定義「學生」結構體陣列
struct student {
char name[20];
int id;
float score;
};
// 初始化全班資料(台灣學號範例)
struct student class[3] = {
{"Alice", 410530, 88.5},
{"Bob", 410531, 76.0},
{"Carol", 410532, 92.3}
};
// 計算全班平均分數
float avg = 0;
for(int i = 0; i < 3; i++) {
avg += class[i].score;
}
printf("平均分數: %.1f\n", avg/3);
4.2 結構體陣列與指標
// 用指標遍歷結構體陣列
struct student *ptr = class; // 陣列名稱即為首元素地址
for(int i = 0; i < 3; i++) {
printf("%s的學號: %d\n", (ptr+i)->name, (ptr+i)->id);
}
5. 巢狀結構
5.1 基本巢狀結構
// 定義「日期」與「學生」結構體
struct date {
int year;
int month;
int day;
};
struct student {
char name[20];
struct date birthday; // 巢狀結構
};
// 初始化與存取
struct student s1 = {
"David",
{2000, 9, 15} // 巢狀初始化
};
printf("%s的出生年份: %d\n", s1.name, s1.birthday.year);
5.2 實際應用:圖書管理系統
struct publisher {
char name[50];
char country[20];
};
struct book {
char title[100];
struct publisher pub; // 巢狀結構
float price;
};
// 出版社範例
struct book b1 = {
"山賊王",
{"西立", "台北"},
580.0
};
6. 聯合體(union)入門
聯合體通常用於實現記憶體共享
6.1 聯合體基本特性
union data {
int i;
float f;
char str[20];
};
// 記憶體共享示範
union data d1;
d1.i = 10;
printf("整數值: %d\n", d1.i); // 輸出10
d1.f = 3.14;
printf("浮點數值: %f\n", d1.f); // 輸出3.14
// 此時d1.i的值已被覆蓋!
6.2 聯合體與結構體混用
union mix {
int arr[3];
struct {
int one;
int two;
int three;
} splite;
};
union mix t;
t.arr[0] = 500;
t.arr[1] = 600;
t.arr[2] = 700;
printf("one: %d\n", t.splite.one);
printf("two: %d\n", t.splite.two);
printf("three: %d\n", t.splite.three);
7. 綜合練習
任務:建立「多邊形」資料結構
struct point {
int x;
int y;
};
struct polygon {
char name[20];
int sides;
struct point vertices[10]; // 頂點座標陣列
};
8. 結構體與函數指標
8.1 函數指標成員
// 定義計算器結構體
struct calculator {
char name[20];
float (*operation)(float, float); // 函數指標成員
};
// 定義運算函數
float add(float a, float b) { return a + b; }
float multiply(float a, float b) { return a * b; }
int main() {
struct calculator calc_add = {"加法器", add};
struct calculator calc_mul = {"乘法器", multiply};
printf("3 + 5 = %.1f\n", calc_add.operation(3, 5));
printf("3 * 5 = %.1f\n", calc_mul.operation(3, 5));
return 0;
}
8.2 實際應用:策略模式
// 台灣天氣數據處理範例
struct weather_analyzer {
char location[20];
float (*analyze)(float[], int); // 分析策略
};
float avg_temperature(float temps[], int n) { /*...*/ }
float max_temperature(float temps[], int n) { /*...*/ }
struct weather_analyzer taichung = {
"台中",
avg_temperature // 使用平均溫度策略
};
9. 動態結構體操作
9.1 結構體與動態陣列
struct student {
char name[20];
int id;
};
// 動態建立學生陣列
int n = 5;
struct student *class = malloc(n * sizeof(struct student));
// 初始化資料
for(int i=0; i<n; i++) {
sprintf(class[i].name, "學生%d", i+1);
class[i].id = 410530 + i;
}
free(class); // 釋放記憶體
10. 聯合體的進階應用
10.1 型別轉換技巧
// 檢視float的記憶體表示
union float_converter {
float value;
unsigned char bytes[4];
} fc;
fc.value = 3.14;
printf("IEEE754表示: ");
for(int i = 0; i < 4; i++) {
printf("%02X ", fc.bytes[i]); // 輸出16進位表示
}
10.2 節省記憶體應用
// 台灣便利商店商品資料
struct product {
char name[50];
union {
int quantity; // 一般商品
float weight; // 散裝商品
} stock;
char type; // 'Q'=數量, 'W'=重量
};
struct product p1 = {"茶葉蛋", .stock.quantity=10, 'Q'};
struct product p2 = {"餅乾", .stock.weight=150.5, 'W'};
11. 綜合範例
悠遊卡交易系統模擬
struct transaction {
struct date time;
char location[30];
union {
int bus_route; // 公車路線
char station[20]; // 捷運站名
} transport;
int amount;
};
12. C語言結構體與聯合體重點總結
結構體 (struct)
- 打包不同類型變數
- 用
.
存取變數成員,->
存取指標成員 - 可巢狀定義,建立複雜資料結構
聯合體 (union)
- 共享記憶體空間
- 同一時間只能使用一個成員
- 節省記憶體,用於型別轉換
13. 課堂作業
圓柱與方柱體積計算程式
作業要求
- 設計結構體包含:
- 圓柱(半徑、高)
- 方柱(長、寬、高)
- 使用聯合體儲存不同柱體的參數
- 使用指標操作柱體資料
- 依序輸入2種柱體的參數後,自動計算並顯示體積和表面積
程式碼 架構
#include <stdio.h>
#define PI 3.14159
// 聯合體儲存柱體參數
union ColumnData {
struct { float radius, height; } cylinder; // 圓柱
struct { float length, width, height; } prism; // 方柱
};
// 主結構體
typedef struct {
int type; // 1=圓柱, 2=方柱
union ColumnData data;
} Column;
// 計算體積
float volume(Column *col) {
if(col->type == 1) { // 圓柱
...
}
else { // 方柱
...
}
}
// 計算表面積
float surface_area(Column *col) {
...
}
int main() {
Column columns[2]; // 儲存2種柱體
// 輸入圓柱參數
printf("請輸入圓柱的半徑和高度: ");
...
// 輸入方柱參數
printf("請輸入方柱的長、寬、高: ");
...
// 計算並輸出結果
printf("\n計算結果:\n");
...
return 0;
}
執行範例
請輸入圓柱的半徑和高度: 3 5
請輸入方柱的長、寬、高: 2 3 4
計算結果:
1. 圓柱: 體積=141.37, 表面積=150.80
2. 方柱: 體積=24.00, 表面積=52.00