応用プログラミング演習 2012年度 第5回 †[edit]
課題A 締切: 今回の演習終了20分前(2点) †[edit]
番号 | 名前 | 年齢 | 視力 |
3 | Uni | 100 | 0.1 |
666 | Henako | 18 | 5 |
1055 | Hogeo | 40 | 1.5 |
構造体を利用して,上記の各行をひとまとまりのデータとみなして処理するプログラムを作ろう.
ただし,次の条件を満たすようにすること.
- ソースファイル名は ex05a.c とする.
- 次の内容のテキストファイル(ファイル名を data4ex05a.txt とする)があったとする.
3 Uni 100 0.1
666 Henako 18 5
1055 Hogeo 40 1.5
これを入力としてこのプログラム(実行形式のファイル名を ex05a とする)を次のように実行すると次の出力が得られる.
$ ./ex05a < data4ex05a.txt
num: 666 name: Henako age: 18 sight: 5.0
num: 3 name: Uni age: 100 sight: 0.1
num: 1055 name: Hogeo age: 40 sight: 1.5
- 元のファイルと順序が入れ替わっている箇所があることに注意.
- nameの文字列は,名前に最大99文字使えるように大きさを考えること.
- 視力の数値の表示形式に注意.
- 上述の結果が得られるように,次のようなプログラムを作成すること
- 構造体の変数も配列にできるので,配列を使いたくなるかもしれませんが,ここではばらばらの変数を使えばよいです(構造体変数の配列は次回の講義で登場します).
#include <stdio.h>
「ひとり分のデータを格納するための構造体を定義する」(typedefを使って適当な型名をつけること)
int main(void)
{
「構造体変数の宣言」
scanf("%d %s %d %lf", 「ひとつめの変数に値を入れる」);
scanf("%d %s %d %lf", 「ふたつめの変数に値を入れる」);
scanf("%d %s %d %lf", 「みっつめの変数に値を入れる」);
「3つの変数のうち2つの内容をいれかえる」(構造体を使う利点をいかすこと)
printf(「ひとつめの変数の内容を表示」);
printf(「ふたつめの変数の内容を表示」);
printf(「みっつめの変数の内容を表示」);
return 0;
}
課題B 締切: 今回の演習終了20分前(2点) †[edit]
次のように cp コマンドを実行すると,prime.h と prime.c という二つのファイルを入手できる.
$ cp /home/sample/takataka/aprog2012/prime.* .
ちなみにこのコマンドを実行すると何がおこるかを説明すると…
- 「*」は,「0文字以上の任意の文字」を表すので,prime.h と prime.c の両方がコピー元に指定される(もしも上記ディレクトリ内に他にも prime.hoge とかいうファイルがあったとしたらそれも).
- コピー先の指定が「.」つまりカレントディレクトリなので,コピー元のファイルたちは名前を変えずにカレントディレクトリにコピーされる
ということになっている.
「*」や「?」(任意の1文字を表す)の解釈はシェルが行っているので,cp 以外のコマンドでもこの技は使える.
$ ls *.c
$ ls ex??x999.c
などを実行してみるとよい.ちなみに,次のように実行すると大変なことになる.
$ rm *
コピーができたら,次のことをしなさい.
- lsコマンドを実行して本当にコピーできたことを確認
- emacs または less でこれらのファイルの中身を眺めてみる
以下のstepでは,この2つのファイルを利用するプログラムを作成する.
その際には,prime.h と prime.c は利用するだけで,それらの中身は変更しない ようにすること.
次のような動作をするプログラムを作りなさい.
- 自分で作成するソースファイルの名前は ex05prime.c とすること.
- 入力された数は配列に格納すること.数の個数は100以下と仮定してよい.
$ ./ex05prime
何個?: 6 ← 6 はキーボードからの入力
0番目: 7 ← 7はキーボードからの入力.以下同様
1番目: 2
2番目: 1024
3番目: 1023
4番目: 8192
5番目: 8191
素数は3個 ← プログラムの出力
prime.{c,h} を見るとわかるように,prime.c には三つの関数が定義されている.
step1のプログラムでは,そのうちひとつはmain()から呼び出されており,もう一つはその関数から呼び出されているが,残りひとつの関数は全く使われていないはずである.
step1のプログラムを改造し,その関数をmain()から呼び出すようにしなさい.
ここまでできたらチェックをうけよう.
課題C 締切: 次回の演習開始直後(4点) †[edit]
次のような動作をするプログラムを作成しなさい.
$ ./ex05search
線形探索するよん
0以上の整数から成るデータを扱えるよん
データは何件?: 5
0番目のデータ(0以上の整数)を入力してね: 10
1番目のデータ(0以上の整数)を入力してね: 37
2番目のデータ(0以上の整数)を入力してね: 26
3番目のデータ(0以上の整数)を入力してね: 10
4番目のデータ(0以上の整数)を入力してね: 123
データは5件やな
キー値を入力してね(負の数だと終了するよ): 37
その値は1番目にあるよ
キー値を入力してね(負の数だと終了するよ): 10
その値は0番目にあるよ
キー値を入力してね(負の数だと終了するよ): 36
その値はないみたい
キー値を入力してね(負の数だと終了するよ): -2
ばいばい
ただし,以下の指示に従うこと.
- ソースは次の3つのファイルから成るものとする
- 関数mainの定義を含むソースファイル ex05search.c
- 関数LSearchの定義を含むソースファイル search.c
- 関数LSearchのプロトタイプ宣言を含むヘッダファイル search.h
- 入力されるデータが0以上の整数であるかどうかのチェックは,省略して構わない(余裕のある人は,なぜこのような条件が必要なのかを考えるとともに,チェックするように(負数を入力すると再入力を促すとか)改良してみるとよい)
- 関数LSearchは次のような仕様とする(まずは関数LSearchの定義を紙に書いてみること)
- 引数は,int型配列,その要素数,キーの値,の3つ
- 配列中にキーの値と一致する要素が見つかればその番号(配列の添字)を返し,見つからなければ-1を返す
- 探索アルゴリズムは線形探索とする
- この関数中ではscanfもprintfも使わない(デバグ中は別ですが)
- 配列中に同じ値が複数含まれている場合のことは考慮しなくてよい(上記の実行例からわかるように,最初に見つけたものの番号を返すようにしておけばよい)
ヒント: mainの側での1回の探索の手順はこんな感じですね.
- キー値を入力してもらう
- それが負だったらほげほげ
- LSearchを呼ぶ
- 見つけたかどうかに応じてほげほげ