応用プログラミング及び実習 2017年度 第3回†
- 実習のすすめ方について AProg/2017/ex00
- Linux環境での操作についてわからないことがあったら Docs/4UNIXBeginners
- 締切に間に合わずチェックを受けられなかった課題は自分で完成させておくこと. 先の回には,過去の課題のプログラムを改造して新たなプログラムを作る課題があります. 締切後には点数はつきませんが,質問等は随時どうぞ.
課題A(self) 締切: 今回の実習終了時†
実習第1回の課題D-2のプログラムを元にして,次のようなプログラムを作成しなさい.
- ソースファイル名は ex03x999.c とする
- check cp コマンドを使って ex01x999.c をコピーして修正するのがらくちんでしょう.エディタを2つ開いてマウスでコピー&ペーストとか,手間かかるし間違いやすいし超かっこ悪いのでやめましょう.
- データ件数とデータを標準入力から受け取るかわりにファイルから読み込むようにする.また,出力先は従来どおり標準出力とする
- キー入力をうながす「何個?」「0番目:」のようなメッセージは出力をやめよう
- 読み込むテキストファイルは data4ex03a.txt という名前とし,データ件数とデータは適当に自分で決めること
- ファイルを開く際のエラー処理を行うこと
- check 次の箇所がソースプログラム中のどこか答えなさい
- ファイルを開く所
- ファイルを閉じる所
- ファイルの内容を読み込んでいる所
- ファイルポインタの変数を宣言している所
- check 正しく動くことを確認したら,読み込むテキストファイルの内容を変更して再度実行してみよう
- check 次のようにわざと間違えて動作を確認しよう
- 開くファイルの名前を間違えてみる
- ファイルに記したデータ件数を実際の数より少なくしてみる(現在のプログラムだと,逆に多い方に間違えると,入力を待ったままプログラムが終了しなくなるでしょう)
課題B(self) 締切: 今回の実習終了時†
下記のプログラムソースは,標準入力からPGMファイルの名前を受け取り,そのファイルを開いてヘッダの情報を読み取り,それを標準出力に出力することを意図したプログラムである(関数 getnum と readPGMHeader については,関数定義の上のコメントに書いてあることがわかればok.中身についてきちんと理解することは,この課題の要件ではありません).これを ex03b.c という名前で保存し,次のことをやりなさい.
- 次のことをやってプログラムを完成させなさい.この2箇所の他には修正の必要はないはず.
- 空欄となっている fopen の引数を書きなさい
- 空欄となっている readPGMHeader の引数を書きなさい
- 実際に画像ファイルを読み込ませる等して動作確認しなさい
- 次の問に対する答えを考えなさい(白字で答えが書いてあります)
- このプログラムで正しく扱えるファイル名の文字数は最大何文字か: 答 配列の大きさは100文字分あるが,文字列の最後に '\0' を付ける必要があるので,文字数の最大は99
- 次の三通りの条件でプログラムを実行した場合,23行目と26行目の if 文の条件判定の結果は,真(true)/偽(false)/そもそもそのif文が実行されない,のいずれになるか答えなさい.また,そのときのプログラムの出力はどうなるか答えなさい.
- ファイル名として,正しいPGM形式のファイルの名前を指定した場合(例えば uni3.pgm): 答 23行目は false,26行目は true,出力は自分で確かめよう
- ファイル名として,存在するがPGM形式ではないファイルの名前を指定した場合(例えば ex03b.c): 答 23行目は false,26行目も false,出力は自分で確かめよう
- ファイル名として,存在しないものを指定した場合: 答 23行目は true,26行目は実行されない,出力は自分で確かめよう
#gist(efb87905a4dbdc6bf706);
課題C(TA&takataka) 締切: 後述†
- TAチェック課題としての締め切り: 今回の実習終了20分前
- takatakaチェック課題としての締め切り: 来週月曜13時まで(提出法については AProg/2017/ex00参照)
次の仕様の二つの関数の定義を指定の紙に書いて提出しなさい.
いずれも,課題Bのプログラムに後で追加して使うと想定しよう(したがって,課題Bのプログラムで #define してる定数を使うこと).
- 関数 readPGMBody
- 引数は,ファイルポインタ,画素値を格納する二次元配列,画像の幅,画像の高さ,を表す変数.順序もこの通りで.
- 戻り値はなし
- ファイルポインタで指定されたファイルから画素値を読み込み,2次元配列に格納する.
- readPGMHeader の続きの読み込み処理をするものと考えればよい
- 本当は,指定されたファイルが壊れてる(画素値の数が足りないとか)場合のエラー処理をするのがよいです.でも,それだとプログラムがかなり複雑になるので,ここではエラー処理は考えないことにします
- 関数 writePGM
- 引数は,自分で考えよう.変数の順序等は readPGMHeader や readPGMBody となるべく対応がつくようにしておくのが分かりやすくてよいでしょう.
- 戻り値はなし
- ファイルポインタで指定されたファイルに,引数で渡された内容をPGM画像形式で書き出す
- "P2" を書く部分は,関数内で直接
fprintf(..., "P2\n");
とか書いちゃえばよいでしょう.
check 前回の課題B のプログラムを参考にしたら,ちょこちょこ書き換えて使えますね.
課題D(TA) 締切:次回実習開始直後†
この課題のチェック時には,課題Cの紙を見せてもらいます.なくさないでね.
課題B,課題C,前回の課題C の結果を組み合わせて,指定されたPGMファイルを読み込み,その画素値を反転させ,指定されたPGMファイルに書き出す,というプログラムを作りなさい.
- ソースファイル名は ex03negate.c とする
- 次のような動作をするようにしよう
$ ./ex03negate
入力ファイル名を指定してください: uni3.pgm ← サンプル画像
出力ファイル名を指定してください: ex03negate.c
- check 何も考えずにこの例をそのまま実行すると大変痛い目に遭います. 完成したプログラムでこの例をそのまま実行すると何が起こるか考えて,大変なことにならない実行例を自分で作って試してください
- 出力部分については,以下を参考にするとよい
while(1){
printf("出力ファイル名を指定してください: ");
scanf("%s", fname);
fp = fopen( );
if(fp == NULL){
fprintf(stderr, "ERROR: failed to open %s\n", fname);
}else{
writePGM( );
fclose(fp);
break;
}
}
いきなり完成させようとすると混乱する可能性大です.次のように順を追って作ろう
- cp コマンドで ex03b.c を ex03negate.c にコピーする
- コンパイル&動作確認.この時点では当然課題Bと同じ動作しかしない
- readPGMBody を追加し,main 内の適切な場所で呼ぶ
- コンパイル&動作確認.readPGMBody の結果を出力してないので,見た目の動作は課題Bと同じでしょう
- writePGM を追加し,main に出力処理を書く
- コンパイル&動作確認.画像をコピーすることができるはず
- negate も追加
- コンパイル&動作確認.画素値を反転させるプログラムの完成
課題S & T(おまけ)†
右のリンク先参照 AProg/2016/ex03ST