首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

單鏈表查找報「內存不可讀」:經典賦值誤判錯誤定位

     編輯:程式設計疑難解答

錯誤代碼片段

while (p->num != num) {
    p = p->next;
    if (p = NULL) {  // 錯誤在這裡!
        printf("未查詢到該學生\n");
        return;
    }
}

錯誤本質

if (p = NULL) 是賦值操作而非比較操作:

  1. 將 NULL (0) 賦值給指針 p
  2. 表達式值為 0 (false)
  3. if 判斷為假,不進入錯誤處理分支
  4. 循環繼續,嘗試訪問 p->num → 解引用空指針 → 內存不可讀崩潰

正確寫法

// 方法一:比較操作符 ==
if (p == NULL) { ... }

// 方法二:防禦性編程(推薦)
if (NULL == p) { ... }  // 若誤寫 = 編譯器報錯

// 方法三:循環條件前置判斷
while (p != NULL && p->num != num) {
    p = p->next;
}
if (p == NULL) {
    printf("未查詢到該學生\n");
    return;
}

完整修正函數

void selectnum(stu *head) {
    int num, j;
    stu *p = head;
    
    printf("輸入要查詢的學號\n");
    scanf("%d", &num);
    
    // 修正:先判斷指針有效性
    while (p != NULL && p->num != num) {
        p = p->next;
    }
    
    if (p == NULL) {
        printf("未查詢到該學生\n");
        return;
    }
    
    printf("信息如下:\n");
    printf("學號\t姓名\t電話\t\t郵箱\t地址\t生日(年 月 日)\n");
    printf("%d %s %s %s %s %d %d %d\n", 
           p->num, p->name, p->call, p->email, p->address,
           p->b.year, p->b.month, p->b.day);
    
    printf("輸入: 1繼續.\n2結束.\n");
    scanf("%d", &j);
    if (j == 1) return;
    else baymanu(); // 假設為菜單函數
}

調試技巧總結

  1. 編譯器警告:開啟 -Wall -Wextra,GCC/Clang 會警告「assignment in condition」
  2. 靜態分析:Cppcheck、Clang Static Analyzer 可自動檢測
  3. 調試器斷點:觀察 p 變化,發現變為 NULL 后仍繼續循環
  4. 代碼規範:常量在左 (NULL == p) 形成肌肉記憶

擴展:鏈表常見陷阱

  • 頭節點處理:帶頭節點 vs 不帶頭節點
  • 插入/刪除時前驅節點丟失
  • 釋放內存后未置空導致野指針
  • 循環鏈表終止條件判斷錯誤

這個錯誤是 C/C++ 初學者的「必經之路」,養成常量左值比較習慣能從根源杜絕。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved