第10回 コーディング(2)(6月22日)

■ 選手データの取り込み(再考)

選手のデータは、2種類ある。1つは、名前、生年月日、国籍、優勝回数などの基本的なデータで、すべての選手について記載されている。もう1つは、前回の演習で扱ったスコアテーブルである。

今回の演習では、これら2種類のデータをロードして、ネームカードの配列変数に格納する部分のコーディングを行う。

データとサブルーチンの関係を図に示す。

この図には、前者のデータが f1_pilot_info.txt、後者のデータが f1_score_table.txt という名称で記されている。前者のデータをロードするプログラムは、load_pilot_info というサブルーチンであり、後者のデータをロードするプログラムは、load_score_table というサブルーチンである。ロードしたネームカードを単純に表示するプログラムは、prac1001 や prac1002 である。

load_pilot_info では、ネームカードの配列を新規に作成し、データを格納する。

load_score_table では、既に作成されたネームカードに、f1_score_table.txt から読み込んだデータを追加する。

■ 基本データの取り込み(load_pilot_info)

f1_pilot_info.txt

まず、f1_pilot_info.txt の形式を確認しておこう。

このファイルは、タブ区切りテキストである。文字コードは euc コードである。タブ区切りテキストは、Excel などの表計算アプリケーションで読み書きができる。

表の形式であるので、各列について説明する。列は、左の列から順に、「ドライバー番号」、「日本語名」、「英語名」、「短縮名」、「ファイル名」、「チーム名」、「ポールポジションの回数」、「ファステストラップの回数」、「優勝回数」、「総得点数」、「生年月日」、「国籍」、「身長」、「体重」を表わす。

ここのファイルを使おう:⇒f1_pilot_info.txt (ここのファイルは、自動抽出したので、誤りがあるかもしれない…。ちなみに、抽出プログラム一式は、Info.tgzである。暇があったら見て下さい。なお、tgz ファイルの解凍は、tar -zxf Info.tgz である。)

load_pilot_info

ここのサブルーチンでは、(1)ファイルのオープン, (2)ネームカードの配列の確保, (3) ファイルのロードと配列への格納, (4) ファイルのクローズ, (5) 結果のリターン を行う。

このうち (3) については、タブ区切テキストの処理をしなければならない。そこで、次の3つのサブルーチンを作成し、tabstr.c とする。
・指定番目のセルへのポインタの検出
【関数名】char *tabstr_skip(char *line, int n)
【引  数】line ... タブ区切りされた文字列
          n    ... 抽出したいセルの番目
【返り値】セルの文字列の先頭へのポインタ。
          指定したセルの番目が不適切であった場合 NULL を返す。
【方  式】タブの出現回数が指定数未満の間、非タブ文字を読み飛ばす。

・境界記号までの文字列のコピー
【関数名】void tabstr_get_cell(char *src, char *dst, int sz)
【引  数】src ... コピー元
          dst ... コピー先
          sz  ... コピー先の文字列の領域サイズ。sz - 1 文字(バイト)までコピー可能。
【返り値】なし
【方  式】境界記号(\t, \n, \0)が検出されるか、コピー先の領域を越える直前までの間
          文字のコピーを繰り返す。

・指定番目のセルのコピー
【関数名】void tabstr_get_cell_at(char *src, int n, char *dst, int sz)
【引  数】src ... コピー元
          n   ... コピーしたいセルの番目
          dst ... コピー先
          sz  ... コピー先の文字列の領域サイズ。sz - 1 文字までコピー可能。
【返り値】なし
【方  式】tabstr_skip と tabstr_get_cell を用いて実現する。
          tabstr_skip が NULLを返す場合 dst の先頭に '\0' を代入する。

練習1

準備済みのファイル tabstr.c には、肝心なところで、行の順序がランダムに置き換えられている。正しく動作するように、行の順序を修正せよ。

準備済みのファイル load_pilot_info.cは、上述の処理(1)〜(5)を行うように作られている。しかし、選手の画像ファイルの取り込みができていない。適切なところにプログラムコードを追加せよ。

次のファイルを使用して動作確認ができる。

実行方法は、次のとおりである。

  1. make prac1001
  2. ./prac1001 f1_pilot_info.txt

以下に実行結果を示す。
1: F.アロンソ (01_Fernando_Alonso.pgm)
2: L.ハミルトン (02_Lewis_Hamilton.pgm)
3: G.フィジケラ (03_Giancarlo_Fisichel.pgm)
4: H.コバライネン (04_Heikki_Kovalainen.pgm)
5: F.マッサ (05_Felipe_Massa.pgm)
6: K.ライッコネン (06_Kimi_Raikkonen.pgm)
7: J.バトン (07_Jenson_Button.pgm)
8: R.バリチェッロ (08_Rubens_Barrichello.pgm)
9: N.ハイドフェルド (09_Nick_Heidfeld.pgm)
10: R.クビサ (10_Robert_Kubica.pgm)
10: S.ベッテル (10_Sebastian_Vettel.pgm)
11: R.シューマッハ (11_Ralf_Schumacher.pgm)
12: J.トゥルーリ (12_Jarno_Trulli.pgm)
14: D.クルサード (14_David_Coulthard.pgm)
15: M.ウェーバー (15_Mark_Webber.pgm)
16: N.ロズベルグ (16_Nico_Rosberg.pgm)
17: A.ブルツ (17_Alexander_Wurz.pgm)
18: V.リウッツィ (18_Vitantorio_Liuzzi.pgm)
19: S.スピード (19_Scott_Speed.pgm)
20: A.スーティル (20_Adrian_Sutil.pgm)
21: C.アルバース (21_Christijan_Albers.pgm)
22: 佐藤琢磨 (22_Takuma_Sato.pgm)
23: A.デビッドソン (23_Anthony_Davidson.pgm)

■ スコアテーブルの取り込み(load_score_table)

基本的には、この部分のプログラムは前回の演習で作成した。今回の演習で異なる部分は、f1_score_table.txt から取り込んだデータを、ネームカードの配列に追加するところである。

スコアテーブルから取り込んだデータは、名前をみて、ネームカードの配列のしかるべきところに追加されなければならない。そこで、次のサブルーチンを追加する。
・同名の人物を配列から検索
【関数名】int find_same_person( NameCard **ncarray, NameCard *nc )
【引  数】ncarray ... ネームカードの配列
          nc      ... 検索のキーとなるネームカード
【返り値】同名の人物についての配列番号
【方  法】ncarray の先頭から順に、名前の文字列比較により、検索する。
          もし、検索で見付からない場合はエラー終了。

練習2

準備済みのファイル load_score_table.cには、上記の find_same_person の部分の行がランダムに入れ替えられている。正しく動作するように修正せよ。また、スコアテーブルの情報をネームカードの配列にコピーするところで、合計得点のコピーができていないので、それができるように修正せよ。

次のファイルを使用して動作確認ができる。

実行方法は次のとおりである。

  1. make prac1002
  2. ./prac1002 f1_pilot_info.txt f1_score_table.txt

以下に実行結果を示す。
1: F.アロンソ (01_Fernando_Alonso.pgm) RANK: 2 TOTAL: 48
2: L.ハミルトン (02_Lewis_Hamilton.pgm) RANK: 1 TOTAL: 58
3: G.フィジケラ (03_Giancarlo_Fisichel.pgm) RANK: 6 TOTAL: 13
4: H.コバライネン (04_Heikki_Kovalainen.pgm) RANK: 8 TOTAL: 12
5: F.マッサ (05_Felipe_Massa.pgm) RANK: 3 TOTAL: 39
6: K.ライッコネン (06_Kimi_Raikkonen.pgm) RANK: 4 TOTAL: 32
7: J.バトン (07_Jenson_Button.pgm) RANK: 0 TOTAL: 0
8: R.バリチェッロ (08_Rubens_Barrichello.pgm) RANK: 0 TOTAL: 0
9: N.ハイドフェルド (09_Nick_Heidfeld.pgm) RANK: 5 TOTAL: 26
10: R.クビサ (10_Robert_Kubica.pgm) RANK: 7 TOTAL: 12
10: S.ベッテル (10_Sebastian_Vettel.pgm) RANK: 16 TOTAL: 1
11: R.シューマッハ (11_Ralf_Schumacher.pgm) RANK: 15 TOTAL: 2
12: J.トゥルーリ (12_Jarno_Trulli.pgm) RANK: 10 TOTAL: 7
14: D.クルサード (14_David_Coulthard.pgm) RANK: 12 TOTAL: 4
15: M.ウェーバー (15_Mark_Webber.pgm) RANK: 14 TOTAL: 2
16: N.ロズベルグ (16_Nico_Rosberg.pgm) RANK: 11 TOTAL: 5
17: A.ブルツ (17_Alexander_Wurz.pgm) RANK: 9 TOTAL: 8
18: V.リウッツィ (18_Vitantorio_Liuzzi.pgm) RANK: 0 TOTAL: 0
19: S.スピード (19_Scott_Speed.pgm) RANK: 0 TOTAL: 0
20: A.スーティル (20_Adrian_Sutil.pgm) RANK: 0 TOTAL: 0
21: C.アルバース (21_Christijan_Albers.pgm) RANK: 0 TOTAL: 0
22: 佐藤琢磨 (22_Takuma_Sato.pgm) RANK: 13 TOTAL: 4
23: A.デビッドソン (23_Anthony_Davidson.pgm) RANK: 0 TOTAL: 0

■ 小レポート

まずは、練習1と練習2を完成させる。修正した個所を全て、henkou.c というファイルにコピーせよ。コピーは、関数の単位とせよ。henkou.c をプリントアウトして、変更した行に下線を引き、提出せよ。


(c) Masato TOKUHISA (2007, June 20th.)