struct LIST * newList( struct LIST ** pstart){ struct LIST *p, *new; p = *pstart; new = (struct LIST *) malloc(sizeof(struct LIST)); new->next = NULL; if(p!=NULL){ /* リストに要素が存在するとき */ while(p->next!=NULL){ /* リストの末尾を探す */ p=p->next; } p->next = new; /* リストの末尾につなげる */ }else{ *pstart = new; /* 最初の要素の場所を *pstart に */ } return new; } |
リストでは後戻りは出来ないので、先頭のオブジェクトへのポインタは
必ず覚えていなければならない。上の関数 newList()
はそうした
リストの先頭オブジェクトへのアドレスを引数に取る。関数内部では、
まず、新しいオブジェクトを malloc() で割り当て、
それの後ろにはもうデータがないので最初から next に NULL を代入し
ておく。
次に、先頭のオブジェクトへのポインタが NULL でないならば、リストにいくらかの
オブジェクトが連なっているのであるから、
先頭から順に次のオブジェクトへのアドレスを取り出し、最後のオブジェクト
になるまで移動し、先に確保したオブジェクトをこのリストの最後の
オブジェクトの後ろにぶら下げるために、そのアドレス(new)を
最後のオブジェクトの next に入れている。
(図 )。
この例では、データ本体に対しては何もしていないが、それは別の問題で
ある。一方、引数を struct LIST **
にしているのは次の削除
との関係で統一をとっているからであり、使うときには実際の
リストの先頭へのアドレスを保持しているポインタ変数のアドレスを
渡すようにする。これは特にリストの先頭へのポインタが外部の関数に
あるときに、どうやってその先頭へのポインタの中身を書き換えるかと
いう問題であり、実際上の例でもリストに要素が一個もない時には、
このリストの先頭へのポインタを pstart
に保存しておく必要
があるのであった。従って、この関数を実際に使う場合には以下のように
して使う必要がある。
struct LIST *start=NULL; ... newList(&start); |