/home/course/prog1/public_html/2024/ex/ex03/
より、以下のファイルをコピーしておくこと。
input1.txt, input2.txt, output1b_sample.txt, output3_sample.txt
A問題(50点)
以下のプログラムは、テキストファイルinput1.txt を開き、その内容を1文字づつ読み込んで標準出力に表示するとともに、ファイルoutput1.txtに書き込むことでテキストファイルの内容をコピーする。また、読み取った文字数と行数を記録して最後に標準エラー出力に表示を行う。
さらに、stdlib.h
をインクルードしてexit()
関数を使用して、ファイル操作時にエラーが発生した際にはメッセージを標準エラー出力に表示した上でプログラムを強制終了するようにしている(exit()
関数についてはプログラミング入門ハンドアウトのLec12-13 (p.67)を参照のこと)。
#include <stdio.h> #include <stdlib.h> /* <stdlib.h> はexit関数の利用のために必要 */ /* プログラミング入門ハンドアウトのLec12-13 (p.67)を参照のこと */ int main() { char c; /* 文字読み取り用の変数 */ int count = 0; /* 読み取り文字数記録用の変数 */ int lcount = 0; /* 読み取り行数記録用の変数 */ /* 入力用と出力用の二つのファイルポインタの宣言 */ /* 複数のファイルポインタを一度に宣言する場合の書式は */ /* ハンドアウトLec03-14 (p.96) を参照 */ FILE ____________; /* 入力用ファイルinput1.txtを読み出し指定でオープン */ /* エラーが生じた場合は標準エラー出力にメッセージを表示して終了 */ if((fpin = ____________) == ____________){ ____________(____________, "Failed to open: input1.txt\n"); exit(1); } /* 出力用ファイルoutput1.txtを書き込み指定でオープン */ /* エラーが生じた場合は標準エラー出力にメッセージを表示 */ /* 既に開いている入力用ファイルはクローズしてから終了 */ if((fpout = ____________) == ____________){ ____________(____________, "Failed to open: output1.txt\n"); ____________; exit(2); } /* 入力用ファイルから1文字づつ読み取るのをループで繰り返し */ /* 読み取った文字をprintfで表示するとともに出力用ファイルに書き出し */ /* 読み取った文字数と行数も記録する */ /* ファイル終端まで到達したらループ終了 */ /* 文字の読み取りとファイル終端到達判断の書き方は */ /* ハンドアウトLec03-8 (p.95)、Lec03-9, -11, -12 (p.96) などを参照し */ /* 文字の読み取りと結果の代入、条件判断を同時に行うこと */ while(____________ != ____________){ printf("%c", c); ____________(____________, "%c", c); count++; if(c == '\n') lcount++; } /* 読み取った文字数を含むメッセージを標準エラー出力に表示 */ ____________(____________, "%d characters (%d lines) are read and copied.\n", count, lcount); /* 入力用と出力用の二つのファイルをクローズ */ ____________; ____________; return 0; }
このプログラムの空欄を埋めて、正しく動作するようにせよ。
さらに以下のテストを行い、ファイル操作時のエラー処理の動作確認をするとともに標準出力・標準エラー出力の違いを把握すること。
テキストファイルの内容の確認はcatコマンドで行える。また、2つのファイルの内容の一致・不一致はdiffコマンドを用いて確認できる。
% cat input1.txt C is an imperative, procedural language in the ALGOL tradition. It has a static type system. In C, all executable code is contained within subroutines (also called "functions", though not in the sense of functional programming). "C (programming language)" from Wikipedia (https://en.wikipedia.org/wiki/C_(programming_language)). (Access date: 2024/10/03) % ./a.out C is an imperative, procedural language in the ALGOL tradition. It has a static type system. In C, all executable code is contained within subroutines (also called "functions", though not in the sense of functional programming). "C (programming language)" from Wikipedia (https://en.wikipedia.org/wiki/C_(programming_language)). (Access date: 2024/10/03) 356 characters (2 lines) are read and copied. % cat output1.txt (input1.txtと同じなので略) % diff input1.txt output1.txt % (ファイルが完全に一致した場合は、このように何も表示されない)
標準出力と標準エラー出力へのそれぞれの表示を確認する(ハンドアウトLec03-14, -15 (p.96)参照)。
% ./a.out > prog1_stdout.txt 356 characters (2 lines) are read and copied. (文字数の表示は標準エラー出力に行なっているので、標準出力をリダイレクトしても画面表示される) % cat prog1_stdout.txt (input1.txtと同じなので略)
規定の入力ファイルが存在しない場合の動作を確認する。
% mv input1.txt input1_.txt (ファイルinput1.txtの名称を変更し、input1.txtが存在しない状態にする) % ./a.out Failed to open: input1.txt % (ファイルinput1.txtが開けなかった旨のメッセージが表示される) % mv input1_.txt input1.txt (ファイルinput1.txtの名称を元に戻す)
規定の出力ファイルを作成できない場合の動作を確認する。
% chmod a-w output1.txt (ファイルoutput1.txtの書き込み許可を取り除き、上書きできない状態にする) % ./a.out Failed to open: output1.txt % (ファイルoutput1.txtが開けなかった旨のメッセージが表示される) % rm output1.txt rm: remove write-protected regular file 'output1.txt'? y (ファイルoutput1.txtを削除する。書き込み許可がないファイルを削除する場合確認のメッセージが表示されるのでyと答えること)
次にこのプログラムを変更して、以下のような動作を行うプログラムを作成せよ。
(提出ファイル名: prog01b.c)結果として得られる出力ファイルoutput1b.txtの内容は以下の通りになる。
C is an imperative, procedural language in the ALGOL tradition. It has a static type system. In C, all executable code is contained within subroutines (also called "functions", though not in the sense of functional programming). "C (programming language)" from Wikipedia (https://en.wikipedia.org/wiki/C_(programming_language)). (Access date: 2024/10/03) C IS AN IMPERATIVE, PROCEDURAL LANGUAGE IN THE ALGOL TRADITION. IT HAS A STATIC TYPE SYSTEM. IN C, ALL EXECUTABLE CODE IS CONTAINED WITHIN SUBROUTINES (ALSO CALLED "FUNCTIONS", THOUGH NOT IN THE SENSE OF FUNCTIONAL PROGRAMMING). "C (PROGRAMMING LANGUAGE)" FROM WIKIPEDIA (HTTPS://EN.WIKIPEDIA.ORG/WIKI/C_(PROGRAMMING_LANGUAGE)). (ACCESS DATE: 2024/10/03)
このプログラムでは、ファイルinput1.txtの内容を2回読み込む必要がある。このため、最初の読み込みが完了したあと一度ファイルを閉じ、再度開くようにすること(ハンドアウトLec03-20 (p.97)で紹介されている文字配列などを利用すれば一度のファイル内容読み込みでも同じ動作をさせることができるが、この問題ではそのようにする必要はない)。
小文字を大文字に変換するにはハンドアウトLec01-20 (p.85)のサンプルプログラムlec01-8.cの中に含まれている関数cnvtoupperか、Lec03-16 (p.96)のサンプルプログラムで使われている関数toupperのいずれかを用いればよい。前者を使う場合は関数本体とプロトタイプ宣言はそのまま使用し、関数の利用は今回のプログラムに合わせて適切に行うこと。後者を使う場合はctype.hをincludeする必要がある。また、必要に応じて変数を追加してよい。
output1b.txt が指示通りになっているかを確認するために、 output1b.txtと、 サンプルファイル output1b_sample.txt を diff コマンドを用いて比較するとよい。
B問題(50点)
input2.txt の内容
68 80 42 95 84 67 49 64 28 39 63 47 62 15 52 12 11 21 10 88
result2.txt の内容例
max = 95, min = 10, average = 49.850000また、input2.txtの最終行に自然数1と999を追記したファイルを読み込ませた場合に、 同じプログラムできちんと題意を満たすかどうかを確認すること。
追記した場合のinput2.txt の内容
68 80 42 (中略) 21 10 88 1 999
追記した場合のresult2.txt の内容
max = 999, min = 1, average = 90.772727
まず、以下のような動作をするプログラムを作成せよ。
(提出ファイル名: prog03a.c)結果として得られる出力ファイルoutput3.txtの内容は以下の通りになる。
C is an imperative, procedural language in the ALGOL tradition. It has a static type system. In C, all executable code is contained within subroutines (also called "functions", though not in the sense of functional programming). "C (programming language)" from Wikipedia (https://en.wikipedia.org/wiki/C_(programming_language)). (Access date: 2024/10/03) c is an imperative, procedural language in the algol tradition. it has a static type system. in c, all executable code is contained within subroutines (also called "functions", though not in the sense of functional programming). "c (programming language)" from wikipedia (https://en.wikipedia.org/wiki/c_(programming_language)). (access date: 2024/10/03) )30/01/4202 :etad sseccA( .))egaugnal_gnimmargorp(_C/ikiw/gro.aidepikiw.ne//:sptth( aidepikiW morf ")egaugnal gnimmargorp( C" .)gnimmargorp lanoitcnuf fo esnes eht ni ton hguoht ,"snoitcnuf" dellac osla( senituorbus nihtiw deniatnoc si edoc elbatucexe lla ,C nI .metsys epyt citats a sah tI .noitidart LOGLA eht ni egaugnal larudecorp ,evitarepmi na si C
output3.txt が指示通りになっているかを確認するために、 output3.txtと、 サンプルファイル output3_sample.txt を diff コマンドを用いて比較するとよい。
次に、自分で作成したプログラムの出力output3.txtが、サンプル (output3_sample.txt) と一致しているかをdiffコマンドと同様に調べるプログラムを作成せよ。
(提出ファイル名: prog03b.c)このプログラムは以下のような動作をするものとする。
prog03b.cでの実行例(prog03a.cが正しく動作している場合)
% ./a.out Two files are identical. (output3.txtとoutput3_sample.txtが一致した場合)
prog03a.cが題意通り正しく動作してoutput3.txtがサンプル (output3_sample.txt) 通りになっていると、ファイル不一致の場合の動作確認ができない。ファイルoutput3.txtの一部を書き換えてサンプルとは一致しないようにしてからファイル不一致の場合の動作確認を行うこと。
% echo hoge >> output3.txt (追記のリダイレクトで、ファイルoutput3.txtの末尾に余分な文字を付け加える) % ./a.out Two files are different at 1071 byte. (ファイル不一致の場合は、どこで相違が見つかったのかを表示する)
Extra問題
/home/course/prog1/public_html/2024/ex/ex03/extra/
より、以下のファイルをコピーしておくこと。
vss_*.pbm
(演習問題4)、data05-*.txt
(演習問題5)
(全ファイルをzipでまとめたものを、Zipファイルとして用意したので、必要であればここからダウンロードできる。)
複数の同じサイズの白黒画像を重ね合わせてできる画像を出力するプログラムを作成する。 ここで、画像の重ね合わせとは、白黒画像を透明なシートに印刷し、 位置を合わせてそれらを重ね合わせた時にできる画像と同様のものと考えることとする。 したがって、重ね合わせてできる画像の各画素値は、重ね合わせる画像の同じ位置の画素値が全て白であれば白、 それ以外(一つでもその位置の画素値が黒の画像がある場合)は黒となる。
以下の仕様を満たすように関数 read, write, superpose の中身を埋めて、プログラムを完成させなさい。 ただし、扱う画像ファイルのフォーマットはすべて Plain PBM(プログラミング入門第10回ハンドアウト参照)とする。
「関数 read の仕様」補足)視覚復号型秘密分散法と呼ばれる暗号技術は、画像を複数の画像(分散画像)に分けて暗号化するものである。 この演習問題で扱っている画像の重ね合わせは、この方法で暗号化された情報の復号演算(暗号化された情報を復元して取り出す処理)に相当している。 実行例で使用しているサンプル画像ファイル vss_*.pbm は、視覚復号型秘密分散法で作成された分散画像になっているので、 このプログラムによって秘密画像が復元できることになる。
#include <stdio.h> #include <stdlib.h> #define MAX_W 256 /* 画像の幅の最大 */ #define MAX_H 256 /* 画像の高さの最大 */ #define BUF 256 /* バッファサイズ */ /* 画像の幅,高さ,画素値を格納する外部変数 */ int w, h, i_img[MAX_W * MAX_H], o_img[MAX_W * MAX_H]; int read(); void write(); void superpose(); int main(){ superpose(); write(); return 0; } /* * 入力されたファイル名の Plain PBM 形式画像ファイルを読み込み, * その幅,高さ,画素値をそれぞれ外部変数 w, h, i_img に格納する */ int read(){ FILE *fp; char filename[BUF]; int r; /* 必要に応じて変数宣言を追加 */ printf("ファイル名を入力してください: "); if((r = scanf("%s", filename)) == EOF) return EOF; if((fp = fopen(filename, "r")) == NULL){ fprintf(stderr, "ファイル %s を開けません!\n", filename); exit(1); } /* 仕様にしたがって関数を作成しなさい */ } /* * 外部変数 w(幅),h(高さ),o_img(画素値) で与えられる画像を, * Plain PBM 形式でファイル out.pbm に書き出す */ void write(){ /* 仕様にしたがって関数を作成しなさい */ } /* * 画像ファイルを read 関数を用いて読み込み, * それらを重ね合わせてできる画像の画素値を * 外部変数 o_img に格納する */ void superpose(){ /* 仕様にしたがって関数を作成しなさい */ }
用意した画像は以下の通り
注意: display
コマンドによる画像の表示は、以下の環境で行ってください。
1. 演習室環境
2. VPNによる仮想ネットワーク接続を経由した、VNCによるGUIでのリモートログイン環境
% display vss_panda_1.pbm % display vss_panda_2.pbm % display vss_eye_1.pbm % display vss_eye_2.pbm
実行例
% ./a.out ファイル名を入力してください: vss_panda_1.pbm width = 256, height = 256 ファイル名を入力してください: vss_panda_2.pbm width = 256, height = 256 ファイル名を入力してください: ^D(これは Ctrl-D を意味する) % display out.pbm % ./a.out ファイル名を入力してください: vss_eye_1.pbm width = 256, height = 128 ファイル名を入力してください: vss_eye_2.pbm width = 256, height = 128 ファイル名を入力してください: ^D % display out.pbm %
昇順(小さい順)に並んだ複数の数値(int型に格納可能とする)が入っているファイルが 2 つある。 この 2 つのファイルに入っている数値をすべてまとめて全体を昇順で標準出力するプログラムを作成せよ。 2つのファイルそれぞれに値がいくつ入っているかわからない。また、重複する数値は重複した回数分出力すること。
2つのファイルのファイル名は、コマンド名の後に与えることとする。
% ./a.out data05-1.txt data05-2.txt
この実行例のように、コマンドラインオプションでファイル名などを読み込む方法は、 今後第6回で学ぶ(Lec06-11, -12, -13を見よ)ので参照すること。 以下に例を示す。これを元に解答を作成してもよい。
(提出ファイル名: prog05.c )#include <stdio.h> #include <stdlib.h> int main(int argc, char** argv){ FILE *fpin1, *fpin2; /* 入力ファイルその1を開く */ if ((fpin1 = fopen(argv[1], "r")) == NULL){ printf("Failed to open: %s\n", argv[1]); exit(1); } /* 入力ファイルその2を開く */ if ((fpin2 = fopen(argv[2], "r")) == NULL){ printf("Failed to open: %s\n", argv[2]); fclose(fpin1); exit(2); } /* * 数値の読み込みと処理,および結果を出力する */ /* 開いた入力ファイルをそれぞれ忘れずに閉じて終了する */ fclose(fpin1); fclose(fpin2); return 0; }
実行例
% ./a.out data05-1.txt data05-2.txt -25 -24 -23 -22 -22 -22 -21 -21 -21 -19 -19 -18 -18 -18 -17 -14 -14 -13 -13 -12 -12 -11 -10 -9 -8 -8 -8 -7 -6 -5 -4 -3 -3 0 2 4 4 5 6 6 6 6 6 8 10 12 14 14 15 15 17 17 18 19 19 19 20 23 23 24 %
プログラムのテストは data05-1.txt、data05-2.txt、 data05-3.txt を組み合せて行うこと。組合せは 3 通りある。
出力結果は大きくなるので、リダイレクトを用いると、結果を確認しやすい。
./a.out data05-1.txt data05-2.txt > data05.out
この例ではファイル「data05.out」に結果が出力される。
Unixコマンドで、作成するプログラムと同じ結果を得るためには、
cat data05-1.txt data05-2.txt | sort -n > cmdresult.outとするとファイル「cmdresult.out」に結果が入る。 この結果と自分の結果を演習問題1で紹介した diff コマンドを用いて確認せよ。
diff data05.out cmdresult.out