鏈表是動態數據結構基石。本文通過完整的學生管理系統(初始化、創建、遍歷、查找、刪除、文件存取)講解單鏈表核心操作。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int id; // 學號
char name[20]; // 姓名
float score; // 成績
} Student;
typedef struct Node {
Student data;
struct Node *next;
} Node;
Node *head = NULL; // 全局頭指針
void init() { head = NULL; }
void create() {
int n; printf("輸入學生人數: "); scanf("%d", &n);
Node *tail = NULL;
for (int i = 0; i < n; ++i) {
Node *p = (Node*)malloc(sizeof(Node));
if (!p) { perror("malloc"); exit(1); }
printf("第%d位: 學號 姓名 成績 ", i+1);
scanf("%d %19s %f", &p->data.id, p->data.name, &p->data.score);
p->next = NULL;
if (!head) head = tail = p;
else { tail->next = p; tail = p; }
}
}
void display() {
printf("學號\t姓名\t成績\n");
for (Node *p = head; p; p = p->next)
printf("%d\t%s\t%.2f\n", p->data.id, p->data.name, p->data.score);
}
void search(int id) {
for (Node *p = head; p; p = p->next)
if (p->data.id == id) {
printf("找到: %d %s %.2f\n", p->data.id, p->data.name, p->data.score);
return;
}
printf("學號 %d 不存在\n", id);
}
void delete(int id) {
Node *prev = NULL, *curr = head;
while (curr && curr->data.id != id) {
prev = curr; curr = curr->next;
}
if (!curr) { printf("學號 %d 不存在\n", id); return; }
if (!prev) head = curr->next; // 刪除頭節點
else prev->next = curr->next; // 刪除中間/尾節點
free(curr);
printf("刪除成功\n");
}
void save_to_file(const char *filename) {
FILE *fp = fopen(filename, "wb");
if (!fp) { perror("save"); return; }
for (Node *p = head; p; p = p->next)
fwrite(&p->data, sizeof(Student), 1, fp);
fclose(fp);
}
void load_from_file(const char *filename) {
FILE *fp = fopen(filename, "rb");
if (!fp) return; // 文件不存在視為空
Student tmp;
Node *tail = NULL;
while (fread(&tmp, sizeof(Student), 1, fp) == 1) {
Node *p = (Node*)malloc(sizeof(Node));
p->data = tmp; p->next = NULL;
if (!head) head = tail = p;
else { tail->next = p; tail = p; }
}
fclose(fp);
}
int main() {
load_from_file("students.dat");
int choice, id;
while (1) {
printf("\n1.創建 2.顯示 3.查找 4.刪除 5.保存 0.退出\n選擇: ");
scanf("%d", &choice);
switch (choice) {
case 1: create(); break;
case 2: display(); break;
case 3: printf("輸入學號: "); scanf("%d", &id); search(id); break;
case 4: printf("輸入學號: "); scanf("%d", &id); delete(id); break;
case 5: save_to_file("students.dat"); puts("已保存"); break;
case 0: save_to_file("students.dat"); return 0;
}
}
}
prev 指針,支持反向遍歷、O(1) 尾部插入刪除。void* 數據域 + 函數指針(比較、打印、銷毀)實現通用容器。malloc/free 開銷,避免碎片。malloc 未檢查返回值 → 空指針解引用崩潰。free → 內存洩漏。next 導致鏈表斷裂或死循環。fopen/fread/fwrite 返回值。char *name)直接 fwrite 會寫入指針值而非字符串內容,**必須序列化**。