malloc 強制轉型、NULL 檢查、常見錯誤修正(struct node*)malloc(sizeof(struct node)) 的強制轉型意義malloc 回傳 void*,C 語言允許隱式轉為任何指標型別,不加轉型也合法。(struct node*) 是為了相容 C++(C++ 禁止 void* 隱式轉非 void*),也是防呆好習慣:若未包含 <stdlib.h> 導致 malloc 隱式宣告為 int,轉型會觸發編譯警告/錯誤,提前發現遺漏標頭檔。struct node *create() 回傳型別回傳 struct node*,即指向鏈表頭節點的指標。函數職責:依使用者輸入動態建立節點串成單鏈表,最後回傳頭指標供呼叫者後續操作。
h = null; → C 語言關鍵字是 NULL(大寫),通常定義在 <stdio.h>/<stdlib.h>。null 是未定義識別符,編譯錯誤。printf("Allocation failure\n"); → 左括號為全形中文括號,需改為半形 ( )。q 未初始化else
q->next = p; // 第一次進入 else 時,q 尚未賦值!野指標寫入
q = p;
修正:將 q = p; 移到 if (h == NULL) 之後、else 之前,或改用「尾指標法」:
struct node *head = NULL, *tail = NULL;
while (...) {
p = malloc(...);
p->next = NULL;
if (head == NULL) head = tail = p;
else { tail->next = p; tail = p; }
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NEW (struct node*)malloc(sizeof(struct node))
struct node {
char name[20], tel[9];
struct node *next;
};
struct node *create() {
struct node *head = NULL, *tail = NULL, *p;
char name[20];
printf("name: ");
while (fgets(name, sizeof(name), stdin)) {
name[strcspn(name, "\n")] = '\0'; // 移除換行
if (strlen(name) == 0) break;
p = NEW;
if (!p) { perror("malloc"); exit(EXIT_FAILURE); }
strcpy(p->name, name);
printf("tel: ");
fgets(p->tel, sizeof(p->tel), stdin);
p->tel[strcspn(p->tel, "\n")] = '\0';
p->next = NULL;
if (!head) head = tail = p;
else { tail->next = p; tail = p; }
printf("name: ");
}
return head;
}
int main() {
struct node *head = create();
// 遍列印、釋放記憶體...
return 0;
}
gets 改用 fgets?gets 不檢查緩衝區長度,極易溢位,C11 已移除。fgets(buf, sizeof(buf), stdin) 安全讀取一行,保留 \n 需自行移除。