本文展示一個完整的單鏈表管理系統,包含節點創建、關鍵字查找(返回節點/前驅節點)、指定位置後插入、關鍵字刪除、遍歷打印、文本菜單交互,代碼結構清晰,適合作為數據結構教學參考與基礎組件庫。
#define N 10
typedef struct node {
char name[20];
struct node *link;
} stud;
name 固定長度,實際可改為動態分配。link 自引用指標構成鏈表骨架。creat(n) — 尾插法帶頭節點
stud *creat(int n) {
stud *h, *p, *s;
if ((h = malloc(sizeof(stud))) == NULL) exit(0); // 頭節點
h->name[0] = '\0'; h->link = NULL;
p = h;
for (int i = 0; i < n; i++) {
if ((s = malloc(sizeof(stud))) == NULL) exit(0);
p->link = s;
printf("請輸入第%d個人的姓名: ", i+1);
scanf("%s", s->name);
s->link = NULL;
p = s;
}
return h; // 返回頭節點
}
n 個節點,尾指針 p 移動,O(n) 構建。search(h, x) — 返回目標節點指標
stud *search(stud *h, char *x) {
stud *p = h->link;
while (p) {
if (strcmp(p->name, x) == 0) return p;
p = p->link;
}
printf("沒有查找到該數據!\n");
return NULL; // 隱式返回
}
search2(h, x) — 為刪除服務
stud *search2(stud *h, char *x) {
stud *p = h->link, *s = h;
while (p) {
if (strcmp(p->name, x) == 0) return s;
p = p->link; s = s->link;
}
printf("沒有查找到該數據!\n");
return NULL;
}
s 指向 p 的前驅,刪除時直接 s->link = p->link。insert(p) — 在節點 p 後插入
void insert(stud *p) {
stud *s = malloc(sizeof(stud));
if (!s) exit(0);
printf("請輸入你要插入的人的姓名: ");
scanf("%s", s->name);
s->link = p->link;
p->link = s;
}
del(x, y) — 刪除 y,x 為前驅
void del(stud *x, stud *y) {
stud *s = y;
x->link = y->link;
free(s);
}
print(h)
void print(stud *h) {
stud *p = h->link;
printf("數據信息為:\n");
while (p) {
printf("%s ", p->name);
p = p->link;
}
}
void menu() {
clrscr();
printf("\t\t\t單鏈表C語言實現實例\n");
printf("\t\t|--------------------------|\n");
printf("\t\t| [1] 建立新表 |\n");
printf("\t\t| [2] 查找數據 |\n");
printf("\t\t| [3] 插入數據 |\n");
printf("\t\t| [4] 刪除數據 |\n");
printf("\t\t| [5] 打印數據 |\n");
printf("\t\t| [6] 退出 |\n");
printf("\t\t| 如未建立新表,請先建立! |\n");
printf("\t\t|--------------------------|\n");
printf("\t\t 請輸入你的選項(1-6): ");
}
int main() {
int choose;
stud *head = NULL, *searchpoint, *forepoint;
char fullname[20];
while (1) {
menu();
scanf("%d", &choose);
switch (choose) {
case 1: head = creat(N); break;
case 2:
printf("輸入查找姓名: "); scanf("%s", fullname);
searchpoint = search(head, fullname);
if (searchpoint) printf("找到: %s\n", searchpoint->name);
getchar(); getchar(); break;
case 3:
printf("輸入插入位置後的姓名: "); scanf("%s", fullname);
searchpoint = search(head, fullname);
if (searchpoint) { insert(searchpoint); print(head); }
getchar(); getchar(); break;
case 4:
print(head);
printf("輸入刪除姓名: "); scanf("%s", fullname);
searchpoint = search(head, fullname);
forepoint = search2(head, fullname);
if (searchpoint && forepoint) del(forepoint, searchpoint);
break;
case 5: print(head); getchar(); getchar(); break;
case 6: exit(0);
default: printf("非法輸入!"); getchar(); break;
}
}
}
| 問題 | 風險 | 改進 |
|---|---|---|
scanf("%s") 無長度限制 | 緩衝區溢出 | scanf("%19s", name) 或 fgets |
malloc 失敗直接 exit(0) | 資源洩漏、無優雅降級 | 返回錯誤碼,上層釋放已分配內存後退出 |
| 查找失敗返回 NULL 但調用者未檢查 | 空指標解引用崩潰 | 所有調用處必須判空 |
| 菜單輸入非數字導致死循環 | scanf 留殘留字符 | 檢查 scanf 返回值,清理輸入緩衝區 |
getchar(); getchar(); 吸收換行符 | 不可靠,輸入含空格失效 | 用 while(getchar()!='\n'); 清行 |
全局 N=10 固定容量 | 擴展性差 | 動態分配,無人為上限 |
| 無鏈表銷毀函數 | 退出時內存洩漏 | 實現 destroy(head) 遞歸/迭代 free |