1. 程式人生 > >《 C Primer Plus (第六版)中文版 》 書中的一處勘誤

《 C Primer Plus (第六版)中文版 》 書中的一處勘誤


出錯的地方:
第17章高階資料表示
17.2.1 使用連結串列
17.2 films2.c程式
第574頁
下面是程式清單,紅色框內的程式碼是出錯的地方。


這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述

這裡寫圖片描述
作者的本意是想把current指向連結串列的開頭結點,head指向下個結點,然後free當前結點,並判斷是否是最後一個結點,不是的話就迴圈,儲存下個結點的head的值再賦給curent ,head指向下一個結點,再free當前結點。。。依此類推,直到最後一個結點NULL, 迴圈結束。
表面看這個邏輯沒任何問題。但是由於邏輯上的不嚴謹,這裡程式產生了bug。
這段程式碼有兩個很明顯的錯誤,分析如下:
第一,先不理會這段程式碼迴圈了多少次。迴圈的最後一行free 了current指標 ,然後回過頭來再判斷current是否為NULL.注意,這個地方在使用野指標了。因為free之後,原先申請到的記憶體空間已經返回給系統了,所以current已經指向一個不合法的記憶體空間。此時對current的任何操作都是錯誤的。
第二,因為是先free current再判斷current是否為NULL,所以free的次數會比malloc多一次。
執行上面程式,執行結果顯示是段錯誤,我們來分析為什麼會產生段錯誤。
假設一共有3個結點。迴圈第一次後,head指向第2個結點,第1個結點被free掉。
迴圈第二次後,head指向第3個結點,第2個結點被free掉。
迴圈第三次後,head指向第4個結點,是不存在的結點,為NULL,第3個結點被free掉。
迴圈第四次,current指向第4個結點NULL,head = current -> next 變成了這樣子
head = NULL -> next。然而NULL是系統定義的0地址,我們知道計算機的低地址空間是不允許被訪問的。這裡試圖操作記憶體低地址空間所以就產生了段錯誤。
雖然文章後面也講了films2.c程式的一些不足。但是上面寫到的錯誤明顯是作者的不細心造成的。(也有可能是翻譯錯了,因為英文版的書我沒有看過。)
下面修改之後的程式碼:
// 釋放記憶體
current = head;
while(current != NULL)
{
head = current -> next;
free(current);
current = head;
}
最後說一句,很多程式的BUG都是來源於邏輯上的不嚴謹,還有就是沒有養成好的程式設計習慣。