幾周前, Linus
Torvalds在Slashdot上回答了一些問題。其中有一條引發了開發者們的強烈關注,當被問到他心目中的核心黑客時,他說自己這些日子已經不怎麼
看代碼了,除非是幫别人審查。他稍微暫停了一下,坦言那些“狡猾”的通過檔案名查找高速緩存又抱怨自己能力一般的核心“惡魔”(黑客)才是他欣賞的。
他說:
相反,很多人連低水準的核心程式設計都還沒學好。像lockless用名字查找(name lookup)功能即使不大也不複雜,卻是指針到指針的一個簡單及良好的使用方法。比如,我曾看見過許多人通過跟蹤上一頁條目删除一個單向連結的清單項,然後删除該條目。例如:
if (prev)
prev->next = entry->next;
else
list_head = entry->next;
複制代碼
每當我看到這些的代碼,我會說:“此人不了解指針”。這還是一個可悲的、常見的問題。
如果開發者能夠了解指針,隻需要使用“指向該條目的指針”并初始化list_head,然後貫穿清單,此時無需使用任何條件語句即可删除該條目,隻需通過 *pp = entry->next。
我想我了解指針,但不幸的是,如果要實作删除函數,我會一直保持跟蹤前面的清單節點。這裡是代碼草稿:
不了解指針的人做法:
typedef struct node
{
struct node * next;
....
} node;
typedef bool (* remove_fn)(node const * v);
// Remove all nodes from the supplied list for which the
// supplied remove function returns true.
// Returns the new head of the list.
node * remove_if(node * head, remove_fn rm)
for (node * prev = NULL, * curr = head; curr != NULL; )
{
node * next = curr->next;
if (rm(curr))
{
if (prev)
prev->next = curr->next;
else
head = curr->next;
free(curr);
}
else
prev = curr;
curr = next;
}
return head;
}
這個連結清單很簡單,但可以把每個節點的指針和sentinel值建構成了一個完美的結構體,但是修改這個表的代碼需要很精妙。難怪連結清單功能會常出現在許多面試環節中。
上面執行的代碼是處理從清單頭中删除任何節點所需的條件。
現在,讓我們好好記住Linus Torvalds執行代碼。在這種情況下,我們通過一個指針指向清單頭來貫穿清單周遊修改。
Two star programming:
void remove_if(node ** head, remove_fn rm)
for (node** curr = head; *curr; )
node * entry = *curr;
if (rm(entry))
*curr = entry->next;
free(entry);
curr = &entry->next;
好多了!最關鍵的部分在于:連結清單中的連結都是指針,是以指針到指針是修改連結清單的首選方案。
改進版的remove_if()是一個使用雙重星号的例子,雙重星号象征着兩重間接尋址,再加一個星(third star)又會太過多餘。
英文出自:Wordaligned
<a href="http://www.csdn.net/article/2013-01-10/2813559-two-star-programming" target="_blank">http://www.csdn.net/article/2013 ... wo-star-programming</a>