首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

《C Primer Plus 第五版》中文版示例代碼錯誤分析:ListItemCount 與 Traverse 函數的指針傳遞問題

     編輯:關於C語言

《C Primer Plus 第五版》中文版示例代碼錯誤分析

在研讀《C Primer Plus 第五版》中文版時,筆者發現第 17 章(第 499-500 頁)的兩個示例函數 ListItemCount() 和 Traverse() 存在指針層級不匹配的錯誤。這個問題若不修正,會導致程序運行時發生段錯誤或邏輯錯誤。

問題代碼對比

原書 list.c 中這兩個函數的定義如下:

unsigned int ListItemCount(const List * plist)
{
    unsigned int count = 0;
    Node * pnode = *plist;  // 此處解引用 plist
    while(pnode != NULL)
    {
        ++count;
        pnode = pnode->next;
    }
    return count;
}

void Traverse(const List * plist, void(*pfun)(Item item))
{
    Node * pnode = *plist;  // 同樣解引用 plist
    while(pnode != NULL)
    {
        (*pfun)(pnode->item);
        pnode = pnode->next;
    }
}

然而,在 film3.c 主程序中調用這兩個函數時,傳遞的是 List 類型變量 movies 的地址(即指針):

Traverse(movies, showmovies);        // 傳遞指針
printf("You entered %d movies.\n", ListItemCount(movies)); // 傳遞指針

錯誤根源:函數參數聲明為 const List * plist(指向指針的指針),但調用時傳遞的是 List 類型的指針(即 Node *)。函數內部通過 *plist 解引用,導致實際操作的是指針指向的內容而非鏈表頭節點,造成類型不匹配。

兩種修正方案

方案一:修改函數調用處,傳遞指針的地址

Traverse(&movies, showmovies);
printf("You entered %d movies.\n", ListItemCount(&movies));

方案二:修改函數定義,直接使用傳入的指針(推薦)

unsigned int ListItemCount(const List * plist)
{
    unsigned int count = 0;
    Node * pnode = plist;  // 直接使用 plist,不解引用
    while(pnode != NULL)
    {
        ++count;
        pnode = pnode->next;
    }
    return count;
}

void Traverse(const List * plist, void(*pfun)(Item item))
{
    Node * pnode = plist;  // 直接使用 plist
    while(pnode != NULL)
    {
        (*pfun)(pnode->item);
        pnode = pnode->next;
    }
}

方案二更符合 C 語言慣用模式:List 本身就是指向鏈表頭節點的指針(typedef Node * List),函數參數應直接接收該指針,而非指針的指針。這也是原書英文版的正確做法,中文版在翻譯或排版時可能引入了此錯誤。

總結

此錯誤屬於典型的「指針層級混淆」問題。建議讀者在參考示例代碼時,務必核對函數參數聲明與調用處的實際傳遞類型是否一致。採用方案二修改函數定義可從根本上消除該隱患,也更符合鏈表操作的直觀邏輯。

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