HOME»基本情報技術者平成29年春期問題»午後問9
基本情報技術者過去問題 平成29年春期 午後問9
⇄問題文と設問を画面2分割で開く⇱問題PDF問9 ソフトウェア開発(C)
次のCプログラムの説明及びプログラムを読んで,設問1~3に答えよ。
マーク式試験の答案を採点するプログラムである。問題と受験者の解答の例を,図1に示す。ここでは,unsigned int型のデータは,16ビットのビット列で表し,連続する8ビットが全て0のときは0…0,全て1のときは1…1と表記する。
〔プログラムの説明〕
マーク式試験の答案を採点するプログラムである。問題と受験者の解答の例を,図1に示す。ここでは,unsigned int型のデータは,16ビットのビット列で表し,連続する8ビットが全て0のときは0…0,全て1のときは1…1と表記する。
〔プログラムの説明〕
- 関数 marking は,1回の実行で受験者1人分の答案を採点する。
- 関数 marking の引数の仕様は,次のとおりである。ここで,引数の値に誤りはないものとする。
- 問の数は,numQ である。引数である各配列の要素数も,numQ である。
- 1問当たりの選択肢の個数は16個以下である。
- type[ ] の各要素には,答えを一つマークする問の場合は1,複数個マークする間の場合はマークする個数n(2≦n≦8)が格納されている。
- ansC[ ] の各要素は,16ビットのビット列で,図2の例に示すように,最上位
のビットから1ビットずつ順に選択肢ⓐ,ⓑ,…に対応し,正答の選択肢に対応するビット位置に1が格納されている。他の全てのビットは0である。 - ansE[ ] の各要素は,ansC[ ] と同様の形式で,受験者の解答が格納されている。
- 関数 marking は,各問(要素番号 i:0,1,…,numQ-1)について,表1に示す解答形式に応じた採点方法で採点する。採点結果は mark[i] に格納する。
- 関数 marking から呼ばれる関数 countMarkBits は,引数の値に含まれる1のビットの個数を返却値として返す。
設問1
プログラム1中の に入れる正しい答えを,解答群の中から選べ。
a,b,c に関する解答群
- 2
- 3
- ansC[i]
- ansC[i] & ansE[i]
- ansC[i] | ansE[i]
- ansE[i]
- type[i]
- type[i]+1
解答選択欄
- a:
- b:
- c:
解答
- a=カ
- b=キ
- c=エ
解説
プログラムを埋める問題です。
注:ここでの unsigned int の定義は「16 ビットのビット列で表し、連続する 8 ビットが全て0のときは 0...0 全て 1 のときは 1...1 と表す」と書かれています。
関数の中身を見ていきましょう。
最初の if 文 type[i] == 1 は、type[i] が 1 である、つまり答えを一つだけマークする問題のとき、ansE[i] == ansC[i] (正解) であるならば、1 を格納します。
次の else if 文 (2 <= type[i]) && (type[i] <= 8) は、同様に答えを type[i] = n 個マークする問題のときです。
次の if 文の空欄ですが、採点方法の表によると
「ansE[i] 中の 1 のビットの個数が n + 1 個以上 (必要以上にマークしている) なら 0、n 個以下なら ansC[i] と ansE[i] の対応するビットがともに 1 である個数 (正解したマーク数)」
と書かれていますので、関数 countMarkBits によって ansE[i] の 1 のビットの個数を調べ、それが n = type[i] 個以下ならいいわけですね。よってaにはansE[i]が、bにはtype[i]がそれぞれ入ります。
さらに「n 個以下なら ansC[i] と ansE[i] の対応するビットがともに 1 である個数 (正解したマーク数)」とありますので、countMarkBits によって ansC[i] と ansE[i] の論理積 (AND) の 1 のビットの個数を調べればよいわけです。
ビット列同士の論理積を計算する演算子は「&」ですので、cに入るのはansC[i] & ansE[i]になります。
∴a=カ:ansE[i]
b=キ:type[i]
c=エ:ansC[i] & ansE[i]
注:ここでの unsigned int の定義は「16 ビットのビット列で表し、連続する 8 ビットが全て0のときは 0...0 全て 1 のときは 1...1 と表す」と書かれています。
関数の中身を見ていきましょう。
最初の if 文 type[i] == 1 は、type[i] が 1 である、つまり答えを一つだけマークする問題のとき、ansE[i] == ansC[i] (正解) であるならば、1 を格納します。
次の else if 文 (2 <= type[i]) && (type[i] <= 8) は、同様に答えを type[i] = n 個マークする問題のときです。
次の if 文の空欄ですが、採点方法の表によると
「ansE[i] 中の 1 のビットの個数が n + 1 個以上 (必要以上にマークしている) なら 0、n 個以下なら ansC[i] と ansE[i] の対応するビットがともに 1 である個数 (正解したマーク数)」
と書かれていますので、関数 countMarkBits によって ansE[i] の 1 のビットの個数を調べ、それが n = type[i] 個以下ならいいわけですね。よってaにはansE[i]が、bにはtype[i]がそれぞれ入ります。
さらに「n 個以下なら ansC[i] と ansE[i] の対応するビットがともに 1 である個数 (正解したマーク数)」とありますので、countMarkBits によって ansC[i] と ansE[i] の論理積 (AND) の 1 のビットの個数を調べればよいわけです。
ビット列同士の論理積を計算する演算子は「&」ですので、cに入るのはansC[i] & ansE[i]になります。
∴a=カ:ansE[i]
b=キ:type[i]
c=エ:ansC[i] & ansE[i]
設問2
関数 countMarkBits のプログラムを,プログラム2に示す。次の記述中の に入れる正しい答えを,解答群の中から選ベ。 コメント/* γ */を付した行の代入式を実行するとき,実行前の work の値が 0101 0000 0…0 であれば,実行後の work の値はdとなる。
コメント/* γ */を付した行の代入式を,
work = work && (work - 1);
と変更して,プログラム2の実行を試みた場合,e
コメント/* γ */を付した行の代入式を,
work = work && (work - 1);
と変更して,プログラム2の実行を試みた場合,e
d に関する解答群
- 0001 0000 0…0
- 0100 0000 0…0
- 0100 1111 1…1
- 1001 0000 0…0
e に関する解答群
- 演算子 && と & とは実行する演算の内容が同じなので,正しい結果を返す
- 演算子 && はビットごとの論理積を求めることはしないので,誤った結果を返す
- 変数 work には実行前の値が保持されたまま変わらないので,無限ループになる
解答選択欄
- d:
- e:
解答
- d=イ
- e=イ
解説
countMarkBits のプログラムを追う・読み解く問題です。
このプログラムは引数 unsigned int ans で与えられたビット列の 1 のビットの個数を調べる関数です。
γが実行される前に work = 0101 0000 0...0 ならば、その実行結果は、
work = work & (work - 1)
= 0101 0000 0000 0000 & (0101 0000 0000 0000 - 0000 0000 0000 0001)
= 0101 0000 0000 0000 & 0100 1111 1111 1111
= 0100 0000 0000 0000
= 0100 0000 0...0
となります。よってdは0100 0000 0…0です。
次の設問ですが、このγの記述中の「&」を「&&」に変更したらどうなるかが問われています。
「&」はビット列同士の論理積を計算する演算子ですが、「&&」は左辺および右辺を論理値として評価した時の論理積を返す論理演算子ですので、その結果は true または false となります。よってe に入る説明は「イ」が適切です。
e=イ:演算子 && はビットごとの論理積を求めることはしないので,誤った結果を返す
このプログラムは引数 unsigned int ans で与えられたビット列の 1 のビットの個数を調べる関数です。
γが実行される前に work = 0101 0000 0...0 ならば、その実行結果は、
work = work & (work - 1)
= 0101 0000 0000 0000 & (0101 0000 0000 0000 - 0000 0000 0000 0001)
= 0101 0000 0000 0000 & 0100 1111 1111 1111
= 0100 0000 0000 0000
= 0100 0000 0...0
となります。よってdは0100 0000 0…0です。
次の設問ですが、このγの記述中の「&」を「&&」に変更したらどうなるかが問われています。
「&」はビット列同士の論理積を計算する演算子ですが、「&&」は左辺および右辺を論理値として評価した時の論理積を返す論理演算子ですので、その結果は true または false となります。よってe に入る説明は「イ」が適切です。
//使用する演算子によって結果が異なる例
11110000 & 00001111 = 00000000
11110000 && 00001111 → true && true = true(C言語では0が偽でそれ以外は真となる)
∴d=イ:0100 0000 0…011110000 & 00001111 = 00000000
11110000 && 00001111 → true && true = true(C言語では0が偽でそれ以外は真となる)
e=イ:演算子 && はビットごとの論理積を求めることはしないので,誤った結果を返す
設問3
次の記述中の に入れる正しい答えを,解答群の中から選べ。
解答形式に,順不同形式を追加する。順不同形式とは,答えを一つマークする問が2問以上連続していて,共通の解答群から答えを選んでいくが,その選択の順序は入れ替わってもよい形式である。図3の例では,問21,22,23の順に正答ⓑ,ⓓ,ⓔが設定されているが,これを受験者の解答の例のように異なる順序で解答してもよい。正しい答えが幾つ選択されたかによって,採点結果が決まる。 順不同形式の問題に対する解答を含む答案を採点するために,プログラム1を次のとおり修正した。
図3の順不同形式の問題に対する解答を含む答案を,修正したプログラム1で採点する。ある受験者の解答の採点例として,関数 marking に渡された各配列要素の内容,及びこれらの内容に基づく採点結果を,図4に示す。 また,図4に示す解答の採点が完了した時点で,変数 sumE には値gが格納されている
解答形式に,順不同形式を追加する。順不同形式とは,答えを一つマークする問が2問以上連続していて,共通の解答群から答えを選んでいくが,その選択の順序は入れ替わってもよい形式である。図3の例では,問21,22,23の順に正答ⓑ,ⓓ,ⓔが設定されているが,これを受験者の解答の例のように異なる順序で解答してもよい。正しい答えが幾つ選択されたかによって,採点結果が決まる。 順不同形式の問題に対する解答を含む答案を採点するために,プログラム1を次のとおり修正した。
- プログラム1中のコメント/* α */の行を,次の1行で置き換える。
- プログラム1中のコメント/* β */の行を,次の13行で置き換える。
図3の順不同形式の問題に対する解答を含む答案を,修正したプログラム1で採点する。ある受験者の解答の採点例として,関数 marking に渡された各配列要素の内容,及びこれらの内容に基づく採点結果を,図4に示す。 また,図4に示す解答の採点が完了した時点で,変数 sumE には値gが格納されている
f に関する解答群
g に関する解答群
- 0…0 0…0
- 0000 1000 0…0
- 0101 0000 0…0
- 0101 1000 0…0
解答選択欄
- f:
- g:
解答
- f=ア
- g=イ
解説
プログラムを順不同形式に対応するよう書き換える問題です。
sumC = sumC | ansC[i]
では、正解となるビットを sumC に順次加算していき、複数回答の形式と同じようにしていきます。sumE に関する記述も同じですが、この記述は ansE[i] の 1 のビットの個数が 1 であるときに限られます。ですので、図 4 の例において ansE[20] 及び ansE[21] は if 文を通りますが、ansE[22] については 1 のビットの個数が 2 ですのでif文を通りません。よってgは0000 1000 0…0です。
採点結果については、順不同形式の問題で type[i] = 13 のとき ―つまり順不同の末尾のとき― に、その末尾の mark[i] に正解の個数が格納されますので、図 4 の例では mark[20] 及び mark[21] には 0 が格納されたままになります。そしてmark[22] に正答数が格納されます。この例での正答数は sumE の結果から 1 ですのでfは「ア」になります。
∴f=ア
g=イ:0000 1000 0…0
【総評】
採点方法をしっかり把握してさえいれば、プログラムは比較的簡単なので追いやすいと思います。演算子に関する知識がないと詰まってしまいますので、しっかりと演算子に関する知識も身に着けておきましょう。
※本問の解説は、当サイト掲示板のスレッドNo.[1150]にご投稿いただいたものです。
sumC = sumC | ansC[i]
では、正解となるビットを sumC に順次加算していき、複数回答の形式と同じようにしていきます。sumE に関する記述も同じですが、この記述は ansE[i] の 1 のビットの個数が 1 であるときに限られます。ですので、図 4 の例において ansE[20] 及び ansE[21] は if 文を通りますが、ansE[22] については 1 のビットの個数が 2 ですのでif文を通りません。よってgは0000 1000 0…0です。
採点結果については、順不同形式の問題で type[i] = 13 のとき ―つまり順不同の末尾のとき― に、その末尾の mark[i] に正解の個数が格納されますので、図 4 の例では mark[20] 及び mark[21] には 0 が格納されたままになります。そしてmark[22] に正答数が格納されます。この例での正答数は sumE の結果から 1 ですのでfは「ア」になります。
∴f=ア
g=イ:0000 1000 0…0
【総評】
採点方法をしっかり把握してさえいれば、プログラムは比較的簡単なので追いやすいと思います。演算子に関する知識がないと詰まってしまいますので、しっかりと演算子に関する知識も身に着けておきましょう。
※本問の解説は、当サイト掲示板のスレッドNo.[1150]にご投稿いただいたものです。