第11回 線型リスト・その3(6/19)

今日のキーワード

■ 分割コンパイル

ファイルの準備

前回まで作成してきたリストのプログラムより、定数(define)、構造体宣言、および、関数名宣言の各部分を1つのファイルにまとめ、関数本体の部分をもう1つのファイルにまとめる。そして、メイン関数およびそのサブルーチンを、別のファイルにまとめる。

コンパイル方法

新しいプログラムの追加方法

新しいプログラム list1102.c を追加するには、Makefile に次を追加する。

list1102:	list1102.o numlist.o
		$(LD) list1102.o numlist.o -o list1102

list1102.o:	numlist.h list1102.c
		$(CC) -c list1102.c

また、clean:; についても以下のように変更する。

clean:;		@rm -f *.o core list1101 list1102

後始末

プログラム作成の練習を終えると、make clean コマンドにより、オブジェクトファイル、実行ファイル、および、コアファイル(セグメンテーションフォールト時などに作られる)を削除する。ユーザの使用可能なディスク容量は限られているため、不要なファイルはこまめに削除すること。

□ 演習1

リスト中の偶数である値の総和を求める関数 int list_even_sum(Node *); を list1101.c にならって作成せよ。そして、Makefile に list1102 を追加して、コンパイルおよび動作を確認せよ。デバッグの際、list1102.c を更新すると、list1102.c はコンパイルされるが、lnumlist.c は2回目以降は、コンパイルされないことに注意せよ。

■ 削除

□ 例題

リストの先頭要素を削除する関数は、pop の関数として既に作成した。今回は、指定値と一致するノードを削除する関数 void list_delete(Node *, int); を作成する。なお、削除対象のノードが存在しない場合は、リスト変更をせず、エラー出力もせずに削除関数を終了することとする。
手始めに、演習1と同様に、既存のプログラム(list1102.c)の一部を書き換えて、list_delete 関数を作成せよ。⇒ list1103.c もちろん、 Makefile も更新すること。
list_delete は次のようになる。
void list_delete(Node *root, int num){
  Node *p;

  p は root と同じノードを指す;
  while ( p の指しているノードの次がNULLでない ) {
    if ( p の指しているノードの次のノードの値が num である ) {
      q は p の指しているノードの次のノードを指す
      p の指しているノードの次ノードを、q の指しているノードの次ノードとする
      q の指しているノードを free する
      break;
    }
    p = p -> next;  /* p は p の指しているノードの次ノードとする */
  }
}

□ 演習2

もし、リストが昇順に並んでいることがわかっている(すなわち、insert 操作だけでリストが作られた)場合ならば、delete 操作は途中で中止することができる。つまり、指定値よりも注目しているノードの値が大きい場合は、これ以上ノードを辿っても無駄だからである。そこで、昇順を想定して削除を行う関数 void list_delete_s(Node *, int); を作れ。⇒ prac1101.c なお、削除対象が存在しない場合は、例題と同様に終了する。また、list1103.c と同様、numlist.c は変更せずに、prac1101.c を作成せよ。もちろん、Makefile は更新する。

■ 宿題

数のリストで最初に数字のあるノードを 0 番目とするとき、n 番目のノードを削除する関数 void list_delete_n(Node *, int); を作成せよ。また、該当番目の無い場合は、例題と同様に終了せよ。また、この削除関数は、ファイル prac1102.c に作成せよ。prac1102.c には動作確認のための main 関数を含むこと。
prac1102.c、Makefile、および、動作結果を報告せよ。numlist.c は変更不要のはずなので、提出しないこと。

(c) Masato TOKUHISA, 2003, June.18