HOME»基本情報技術者令和元年秋期問題»午後問9
基本情報技術者過去問題 令和元年秋期 午後問9
⇄問題文と設問を画面2分割で開く⇱問題PDF問9 ソフトウェア開発(C)
次のCプログラムの説明及びプログラムを読んで,設問1,2に答えよ。
入力ファイルの内容を,文字及び16進数で表示するプログラムである。
〔プログラムの説明〕
入力ファイルの内容を,文字及び16進数で表示するプログラムである。
〔プログラムの説明〕
- 関数 dump の引数の仕様は,次のとおりである。
- char *filename
- 入力ファイルのファイル名
- long from
- 表示を開始するバイト位置
- long to
- 表示を終了するバイト位置(値が負の場合はファイルの末尾)
- 入力ファイルは,バイナリファイルとして読み込む。入力ファイル中の各バイトの内容(ビット構成)に制約はない。図1に,入力ファイルの例を示す。
- 入力ファイル中の各バイトの内容を,文字及び16進数で表示する。図2は図1の入力ファイルの先頭から末尾までの表示例であり,図3は同じファイルのバイト位置17から40までの表示例である。
- 表示の様式を,次に示す。説明中の①,②,…は,図中の網掛け部分を指している。
- 入力ファイルのバイト位置 from から60バイトずつを,3行1組で表示する。
- 各組の1行目に各バイトが表す文字を,2行目に各バイトの16進数表示の上位桁を,3行目に同下位桁を,それぞれ表示する。例えば,①のバイトは,文字表示が"i"で,その16進数表示が69である。
- バイトの内容が16進数表示で20~7E以外の場合は,そのバイトが表す文字として,②のように"."を表示する。
- 各組の1行目の行頭に,その組に表示する最初のバイトのバイト位置を10進数で③の形式で表示する。
- 入力ファイルの内容の表示が終わった後,最終行の④の位置には,入力ファイルの終わりに達して終了した場合は"END OF DATA" を,表示を終了するバイト位置に達して終了した場合は"END OF DUMP" を表示する。⑤の位置には,表示した入力ファイルの内容のバイト数を10進数で表示する。
- 入力ファイルのファイルサイズ(バイト数)及び引数 from,to の値は,次の式を満たすものとする。
- to<0の場合:
- to<0≦from<ファイルサイズ<231
- to≧0の場合:
- 0≦from≦to<ファイルサイズ<231
- プログラム中で使用している関数 fgetc(s) は,ストリームsから1文字を読み込んで返す。ファイルの終わりに達しているときは,EOFを返す。
設問1
プログラム中の に入れる正しい答えを,解答群の中から選べ。ここで,b1とb2に入れる答えは,bに関する解答群の中から組合せとして正しいものを選ぶものとする。
a に関する解答群
- chr & 0x0F
- chr & 0xF0
- chr && 0x0F
- chr && 0xF0
b に関する解答群
c に関する解答群
- cnt > from
- cnt >= from
- cnt >= from - 1
d に関する解答群
- cnt == WIDTH - 1
- cnt == WIDTH
- cnt == WIDTH + 1
- pos == WIDTH - 1
- pos == WIDTH
- pos == WIDTH + 1
解答選択欄
- a:
- b:
- c:
- d:
解答
- a=ア
- b=イ
- c=ア
- d=オ
解説
〔aについて〕
〔プログラムの説明〕(4)で「各組の1行目に各バイトが表す文字を,2行目に各バイトの16進数表示の上位桁を,3行目に同下位桁を,それぞれ表示する」とあります。プログラム中のChar型の配列 tblC[]、tblH[]、tblL[] は、256種類の文字それぞれについて1行目の表示文字、2行目の表示文字、3行目の表示文字に対応を保持している変数です(C=Char、H=High、L=Low)。このプログラムでは、入力ファイルの走査に入る前に各バイトが表す文字について文字と表示文字の対応表を作成しています。
下位桁を取り出したいので下位4ビットを1にした 00001111 = 0x0F と chr との論理積(&)をとることになります。∴a=ア:chr & 0x0F
〔bについて〕
入力ファイルの走査を続ける継続条件を満たすように論理演算子(&&または||)を組み合わせます。
whileループを終了しなくてはならないのは次の2通りです。
また、toが負数のときにはファイルの終端に達するまで処理することになっています。単純に cnt <= 0 としてしまうと toが負数のときには即座にwhileループが終了してしまうことになり正しく動作しません。このため処理を継続するのは「toが負数(=to < 0)」及び「cnt <= to」という条件の少なくとも一方を満たす場合となります。よって、b2には「||」が入ります。
∴b=イ:&&,||
〔cについて〕
この分岐条件式が真となるときには、表示文字列を格納する bufC[]、bufH[]、bufL[] に各バイトが表す文字、上位桁、下位桁の情報を格納しています。つまり、表示を開始するバイト位置であるfromに達した以降の処理です。
cntは、現在読み込んでいる文字がファイルの先頭から何文字目かを保持する変数で、初期値が0、fgetc(infile) で文字が読み込まれた直後(whileループの最初)にインクリメントされています。ここで注意すべきは、cの分岐が行われる際には、cntは何文字目かを、fromはバイト位置を表しているということです。具体的に言うと、0バイト目の文字を処理しているときにはcnt=1、1バイト目の文字を処理しているときにはcnt=2というように、n文字目の処理中のときのcntの値は(n+1)になっています。
例えば、fromが10だった場合には10バイト目の文字から出力したいので、cntが11以上のときに表示文字列に格納する処理を行うことになります。よって、cには「cnt > from」が入ります。
∴c=ア:cnt > from
〔dについて〕
この分岐条件式が真となるときには、標準出力に bufC[]、bufH[]、bufL[] の内容を出力する処理が行われます。whileループの中で行われていること、及び出力文字列の行頭、すなわちその組の表示する最初のバイト位置として cnt-WIDTH を指定していることから、この出力は、bufC[]、bufH[]、bufL[] に60バイトが溜まったときに3行1組の出力を行う処理であると判断できます。
bufC[]、bufH[]、bufL[] への格納処理直後にインクリメントしていることからわかるように、現在、bufC[]、bufH[]、bufL[] に格納されているデータ数はposが保持しています。つまり、posがWIDTH(定数で60)に達したら真となる条件式であれば良いわけです。よって、dには「pos == WIDTH」が入ります。
∴d=オ:pos == WIDTH
〔プログラムの説明〕(4)で「各組の1行目に各バイトが表す文字を,2行目に各バイトの16進数表示の上位桁を,3行目に同下位桁を,それぞれ表示する」とあります。プログラム中のChar型の配列 tblC[]、tblH[]、tblL[] は、256種類の文字それぞれについて1行目の表示文字、2行目の表示文字、3行目の表示文字に対応を保持している変数です(C=Char、H=High、L=Low)。このプログラムでは、入力ファイルの走査に入る前に各バイトが表す文字について文字と表示文字の対応表を作成しています。
tblL[chr] = hex[a];
この処理は tblL[] に値を格納しているので、文字のビット列から下位桁(下位4ビット)を取り出すようになっていなければなりません。対象のビット列から特定位置のビット列を取り出すには、取り出したい位置のビットを1にしたビットマスクを用意し、対象ビット列との論理積(AND)を行います。下位桁を取り出したいので下位4ビットを1にした 00001111 = 0x0F と chr との論理積(&)をとることになります。∴a=ア:chr & 0x0F
〔bについて〕
入力ファイルの走査を続ける継続条件を満たすように論理演算子(&&または||)を組み合わせます。
whileループを終了しなくてはならないのは次の2通りです。
- ファイルから読み込んだ文字がEOFのとき
- ファイル中の位置が表示を終了する位置に達したとき
また、toが負数のときにはファイルの終端に達するまで処理することになっています。単純に cnt <= 0 としてしまうと toが負数のときには即座にwhileループが終了してしまうことになり正しく動作しません。このため処理を継続するのは「toが負数(=to < 0)」及び「cnt <= to」という条件の少なくとも一方を満たす場合となります。よって、b2には「||」が入ります。
∴b=イ:&&,||
〔cについて〕
この分岐条件式が真となるときには、表示文字列を格納する bufC[]、bufH[]、bufL[] に各バイトが表す文字、上位桁、下位桁の情報を格納しています。つまり、表示を開始するバイト位置であるfromに達した以降の処理です。
cntは、現在読み込んでいる文字がファイルの先頭から何文字目かを保持する変数で、初期値が0、fgetc(infile) で文字が読み込まれた直後(whileループの最初)にインクリメントされています。ここで注意すべきは、cの分岐が行われる際には、cntは何文字目かを、fromはバイト位置を表しているということです。具体的に言うと、0バイト目の文字を処理しているときにはcnt=1、1バイト目の文字を処理しているときにはcnt=2というように、n文字目の処理中のときのcntの値は(n+1)になっています。
例えば、fromが10だった場合には10バイト目の文字から出力したいので、cntが11以上のときに表示文字列に格納する処理を行うことになります。よって、cには「cnt > from」が入ります。
∴c=ア:cnt > from
〔dについて〕
この分岐条件式が真となるときには、標準出力に bufC[]、bufH[]、bufL[] の内容を出力する処理が行われます。whileループの中で行われていること、及び出力文字列の行頭、すなわちその組の表示する最初のバイト位置として cnt-WIDTH を指定していることから、この出力は、bufC[]、bufH[]、bufL[] に60バイトが溜まったときに3行1組の出力を行う処理であると判断できます。
bufC[]、bufH[]、bufL[] への格納処理直後にインクリメントしていることからわかるように、現在、bufC[]、bufH[]、bufL[] に格納されているデータ数はposが保持しています。つまり、posがWIDTH(定数で60)に達したら真となる条件式であれば良いわけです。よって、dには「pos == WIDTH」が入ります。
∴d=オ:pos == WIDTH
設問2
関数 dump の動作に関する次の記述中の に入れる正しい答えを,解答群の中から選べ。
表示結果の最終行(表示が1行だけの場合はその行)の表示内容について,次の二つのケースを考える。
〔ケース1〕ファイルサイズ=100,from=99,to=99
この場合,最終行の表示内容は"e"となる。
〔ケース2〕ファイルサイズ=0,from=0,to<0
この場合,ファイルサイズ及び from の値がプログラムの説明(5)の条件を満たしていない。このケースについて関数 dump を実行すると,最終行の表示内容は"f"となる。
表示結果の最終行(表示が1行だけの場合はその行)の表示内容について,次の二つのケースを考える。
〔ケース1〕ファイルサイズ=100,from=99,to=99
この場合,最終行の表示内容は"e"となる。
〔ケース2〕ファイルサイズ=0,from=0,to<0
この場合,ファイルサイズ及び from の値がプログラムの説明(5)の条件を満たしていない。このケースについて関数 dump を実行すると,最終行の表示内容は"f"となる。
e,f に関する解答群
- END OF DATA...-1byte(s)
- END OF DUMP...-1byte(s)
- END OF DATA...0byte(s)
- END OF DUMP...0byte(s)
- END OF DATA...1byte(s)
- END OF DUMP...1byte(s)
解答選択欄
- e:
- f:
解答
- e=オ
- f=ウ
解説
ファイルの終端に達した場合でもtoに達した場合でも、最終行の値として cnt-from を出力することは同じですので、cntの値に注目しながらプログラムをトレースして解答を導きます。
〔eについて〕
from及びtoはバイト位置なので、from=99、to=99は、ファイルサイズ100のファイルの最後の文字(99バイト目)のみを出力する指定となります。
まず cnt=0 から始まり、99文字目(98バイト目)までファイルから1文字を読み込むことを繰り返します。from=99 ですので、cnt=99 までは cnt をインクリメントする以外の処理がwhileループで行われることはありません。
100文字目を読み込むと cnt=100 となります。cnt>from となるので、bufC[]、bufH[]、bufL[] に最後1バイトが表す文字、上位桁、下位桁の情報を格納する処理が行われます。
次に fgetc(infile) が実行されると chr にファイルの終端を示すEOFが格納されるので、この時点でwhileループが終了します。chr=EOF、cnt=100、from=99 なので、
∴e=オ:END OF DATA ... 1 byte(s)
〔fについて〕
先程と同様に cnt=0 から始まりますが、ファイルサイズが0なので最初に chr に格納される値がEOFになります。このため、whileループ内の処理が一度も実行されることなく cnt の値は0のままです。chr=EOF、cnt=0、from=0 なので、
∴e=ウ:END OF DATA ... 0 byte(s)
〔eについて〕
from及びtoはバイト位置なので、from=99、to=99は、ファイルサイズ100のファイルの最後の文字(99バイト目)のみを出力する指定となります。
まず cnt=0 から始まり、99文字目(98バイト目)までファイルから1文字を読み込むことを繰り返します。from=99 ですので、cnt=99 までは cnt をインクリメントする以外の処理がwhileループで行われることはありません。
100文字目を読み込むと cnt=100 となります。cnt>from となるので、bufC[]、bufH[]、bufL[] に最後1バイトが表す文字、上位桁、下位桁の情報を格納する処理が行われます。
次に fgetc(infile) が実行されると chr にファイルの終端を示すEOFが格納されるので、この時点でwhileループが終了します。chr=EOF、cnt=100、from=99 なので、
END OF DATA ... 1 byte(s)
が出力されます。∴e=オ:END OF DATA ... 1 byte(s)
〔fについて〕
先程と同様に cnt=0 から始まりますが、ファイルサイズが0なので最初に chr に格納される値がEOFになります。このため、whileループ内の処理が一度も実行されることなく cnt の値は0のままです。chr=EOF、cnt=0、from=0 なので、
END OF DATA ... 0 byte(s)
が出力されます。∴e=ウ:END OF DATA ... 0 byte(s)