元ネタ
Linuxを生み出したリーナス・トーバルズが考える「優れたコード」とは何か?
gigazine.net
とりあえず、すげぇ雑にコード書いてみた。
gccでコンパイル可能( -std=c99 オプション、付けてちょ)。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//
typedef struct IntListItem {
int value;
struct IntListItem *next;
} IntListItem;
//
typedef struct {
IntListItem *head;
} IntList;
void remove_01(IntList *l, IntListItem *target) {
IntListItem *cur = l->head, *prev = NULL;
while(cur != target) {
prev = cur;
cur = cur->next;
}
if(prev) {
prev->next = cur->next;
} else {
l->head = cur->next;
}
}
//
void remove_02(IntList *l, IntListItem *target) {
IntListItem **p = &l->head;
while( (*p) != target ) {
p = &((*p)->next); // ちょっとだけ括弧を追記
}
*p = target->next;
}
int main() {
//
IntListItem *wk_before;
IntListItem *wk_after;
IntList l;
l.head = NULL;
// 作成
for(int i = 0; i < 5; i++) {
wk_after = (IntListItem *)malloc( sizeof(IntListItem) );
wk_after->value = i + 1;
wk_after->next = NULL;
if (l.head == NULL) {
l.head = wk_after;
} else {
wk_before->next = wk_after;
}
wk_before = wk_after;
}
// 表示
IntListItem *wk;
IntListItem *del;
wk = l.head;
while(wk != NULL) {
printf("%d \n", wk->value);
// 削除用のポインタを取得(後のテスト用)
if (wk->value == 5) {
del = wk;
}
wk = wk->next;
}
printf("\n\n");
// 削除
//remove_01(&l, del);
remove_02(&l, del);
// 表示
wk = l.head;
while(wk != NULL) {
printf("%d \n", wk->value);
wk = wk->next;
}
printf("\n\n");
// 削除
//remove_01(&l, l.head);
remove_02(&l, l.head);
// 表示
wk = l.head;
while(wk != NULL) {
printf("%d \n", wk->value);
wk = wk->next;
}
return 0;
}「スタンフォード大学の計算機科学講義「Computer Science 101(CS101)」で紹介されていたコード」がremove_01、ライナスさんのコードがremove_02。
とりあえずどっちも動く事を確認。
大学のほうのロジックは普通に理解。
ライナスさんのほう……あぁなるほど「targetにきたら"その次"にすっとばしてtargetを実質的に骨抜きにする」んだ。
あと「先頭の削除」の時は、初っぱなの処理が「List->head へのポインタ」だから、「*p = target->next」でそのまま書き換わるんだ。
うん「言われて見て熟考したらわかる」んだけど、これを「思いつく」のって、すンごいなぁ………
面白くもあり、高みが遠くもあり。