原代碼在 Listinsert_L 函數中存在三大錯誤:
s->data.name = e.name 嘗試直接指派陣列,C 語言陣列不可作為左值。p 未初始化:while(p && j < i-1) 中 p 為野指標。#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int Status;
typedef struct {
char name[20];
int code;
float score;
} ElemType;
typedef struct LNode {
ElemType data;
struct LNode *next;
} LNode, *LinkList;
// 建立帶頭節點的單向鏈結串列(頭插法,逆序)
void CreateList_L(LinkList *L, int n) {
*L = (LinkList)malloc(sizeof(LNode));
if (!*L) exit(OVERFLOW);
(*L)->next = NULL;
for (int i = 0; i < n; ++i) {
LNode *p = (LNode*)malloc(sizeof(LNode));
if (!p) exit(OVERFLOW);
printf("請輸入第 %d 位學生 (學號 姓名 成績):", i + 1);
scanf("%d %19s %f", &p->data.code, p->data.name, &p->data.score);
p->next = (*L)->next;
(*L)->next = p;
}
}
// 在第 i 位插入元素 (1-based,頭節點後為第 1 位)
Status ListInsert_L(LinkList *L, int i, ElemType e) {
if (i < 1) return ERROR;
LNode *p = *L; // p 指向頭節點,第 0 位
int j = 0;
// 尋找第 i-1 位節點
while (p && j < i - 1) {
p = p->next;
++j;
}
if (!p) return ERROR; // 位置超出長度
LNode *s = (LNode*)malloc(sizeof(LNode));
if (!s) exit(OVERFLOW);
s->data.code = e.code;
strcpy(s->data.name, e.name); // 字串必須用 strcpy
s->data.score = e.score;
s->next = p->next;
p->next = s;
return OK;
}
// 遍歷輸出
void Output(LinkList L) {
LNode *p = L->next;
printf("\n學號\t姓名\t成績\n");
while (p) {
printf("%d\t%s\t%.2f\n", p->data.code, p->data.name, p->data.score);
p = p->next;
}
}
// 釋放整個鏈結串列
void DestroyList(LinkList *L) {
LNode *p = *L;
while (p) {
LNode *tmp = p;
p = p->next;
free(tmp);
}
*L = NULL;
}
int main() {
LinkList list = NULL;
int n, pos;
ElemType e;
printf("請輸入學生數目:");
scanf("%d", &n);
printf("輸入格式:學號 姓名 成績\n");
CreateList_L(&list, n);
Output(list);
printf("\n請輸入要插入的位置 (1 為第一筆):");
scanf("%d", &pos);
printf("請輸入學生資料 (學號 姓名 成績):");
scanf("%d %19s %f", &e.code, e.name, &e.score);
if (ListInsert_L(&list, pos, e) == OK) {
printf("插入成功!\n");
Output(list);
} else {
printf("插入失敗:位置無效\n");
}
DestroyList(&list);
return 0;
}
strcpy 而非直接指派// 錯誤:陣列名不可作左值
s->data.name = e.name;
// 正確:逐字元複製,含結束符
strcpy(s->data.name, e.name);
// 或更安全:
strncpy(s->data.name, e.name, sizeof(s->data.name) - 1);
s->data.name[sizeof(s->data.name) - 1] = '\0';
LNode *p = *L; // 頭節點為第 0 位
int j = 0;
while (p && j < i - 1) { ... }
原代碼 LinkList p; 未初始化,直接進入 while(p && ...) 是未定義行為。
i=1:插在頭節點之後,即新的第一個資料節點i=n+1:插在尾部i>n+1:返回 ERRORLNode *s = malloc(sizeof(LNode));
if (!s) exit(OVERFLOW); // 或返回 ERROR,視設計而定
scanf("%19s", p->data.name); // 限制讀取長度,防緩衝區溢位
| 操作 | 關鍵點 |
|---|---|
| 刪除第 i 位 | 找第 i-1 位節點 p,tmp = p->next; p->next = tmp->next; free(tmp); |
| 查找值 | 遍歷比對,返回指標或位置 |
| 反轉串列 | 三指標法:prev=NULL, curr=head, next 迴圈反轉 next 指向 |
| 合併有序串列 | 歸併邏輯,建立新頭節點 |
| 檢測環 | 快慢指標 (Floyd 判圈算法) |
print *p、print p->next、watch p->data.code。valgrind --leak-check=full ./a.out 檢測記憶體洩漏、無效讀寫。assert(p != NULL) 捕捉邏輯錯誤。單向鏈結串列是 C 語言指標操作的經典練習。核心功力在於:指標初始化、遍歷邊界、記憶體管理、字串複製、插入刪除的指標重接邏輯。掌握帶頭節點的統一處理模式,能大幅減少邊界條件判斷錯誤。