平成26年度秋期午後のC言語問題である問9の私の解き方・考え方について解説していきます。
問題
IPAの公式サイトで公開されています。このページでは問9についての解説を行います。
https://www.jitec.ipa.go.jp/1_04hanni_sukiru/mondai_kaitou_2014h26_2/2014h26a_fe_pm_qs.pdf
問題の概要
利用者ID管理の問題です。ポイントはファイルの読み込みと論理積演算です。
スポンサーリンク
設問1
設問1はプログラムの穴埋め問題です。[ a ]に関しては解説を最後に回させていただきます。
まずは[プログラム]と[プログラムの説明]の対応を見てみましょう。
下記は[プログラム]のα内の処理を[プログラムの説明]の(3)の中の①〜③に対応づけたものになります。
緑枠はprintf()で出力される内容より(3) – ③に記載の処理であることがわかります。
したがって緑枠は「NewFile及びOldFileの両方にあり、特権Sと特権Oの少なくとも一方の付加状況が変わった利用者IDの場合」のみに実行される必要があります。
「NewFile及びOldFileの両方にあり」はstrcmp(NewID, OldID) == 0が成立する場合ですので、[ b ]の条件は「特権Sと特権Oの少なくとも一方の付加状況が変わった利用者IDの場合」を判断するためのものであると予想できます。
また、[プログラムの説明]の(2) – ②に記載の通り特権Sと特権Oの付加情報はそれぞれ属性のビットsとビットoの値で判断可能です。ReadNewRecord関数とReadOldRecord関数より、属性はNewAttrとOldAttrに格納されますので、この二つの変数のビットsとビットoの値が異なる場合が「特権Sと特権Oの少なくとも一方の付加状況が変わった利用者IDの場合」と言えます。
また下の図で示しているように、論理積演算を用いれば特定ビット以外の部分を0にマスクすることができます。
つまりマスク後の値で比較すれば、特定のビット部分のみ比較が可能です。
プログラムの先頭部分でBitSとBitOが定義されており、NewAttrとOldAttrのビットsとビットoの部分のみで比較するためには下記のように、BitS + BitOを計算し、計算結果とNewAttr・OldAttrのそれぞれの論理積結果を比較することで、特権Sと特権Oの値が同じかどうかを調べることができます。
つまり、
NewAttr & (BitS + BitO)
と
OldAttr & (BitS + BitO)
の値が同じであれば特権Sと特権Oの値は変化しておらず、値が異なっていれば、特権Sと特権Oのどちらか・もしくは両方が変化したと判断できます。
プログラムの緑枠部分は「特権Sと特権Oの少なくとも一方の付加状況が変わった場合」に実行する必要があるため、[ b ]の答えは「NewAttr & (BitS + BitO) != OldAttr & (BitS + BitO)」となります。
[ c ]が実行されるときは、(3) – ③の処理後なので、その利用者IDに対する出力が完了した時です。ですので次の利用者IDに対する出力を行うために次のレコードを読み込む必要があります。また、この利用者IDはNewFile、OldFIleに含まれていますので、両方とも新しいレコードを呼ぶ必要あります。したがって[ c ]では、
ReadNewRecord();
ReadOldRecord();
を実行する必要があり、これが答えとなります。
続いて[ d ]をみていきます。
プログラムのオレンジ枠部分は(3) – ①の処理を行っている部分であり、これは「NewFile中にあってOldFile中にない利用者IDの場合」に実行される処理になります。ですので、[ d ]は「NewFile中にあってOldFile中にない利用者IDの場合」かどうかを判断するための条件であることがわかります。
各レコードは利用者IDで昇順にソートされていますので、上から順に1レコードずつ利用者IDが同じかどうかをstrcmp関数で比較していき、strcmp関数の戻り値が負の値の時に「NewFile中にあってOldFile中にない利用者IDの場合」と判断することができます(strcmp関数については(5)に記載)。
実例で示すと下記のようにNewFileの利用者IDであるNewIDがAP005、OldIDがAP006の時にstrcmp関数が負の値となります。実際にAP005はOldfFileには含まれないデータですよね。
以上より[ d ]の答えは「strcmp(NewID, OldID) < 0」となります。
最後に回していた[ a ]は上記のプログラムのループ条件になります。
全レコードに対して出力が完了するまで処理を繰り返す必要がありますので、ループの条件は全レコード出力完了したかを判断するものとなります。
NewFileの全レコードの処理が終了した場合はNewFileがEOFとなり、OldFileの全レコードの処理が終了した場合はOldFileがEOFとなりますので、どちらか一方でもEOFでない場合は処理を続行する必要があります。したがってループの条件である[ a ]の答えは「(NewEof != EOF) || (OldEof != EOF)」となります。
設問2
設問2も設問1と同じ考え方・知識で回答可能だと思います。
まず[ e ]は「NewFile中にあって、属性のビットrが1である利用者ID」であるかどうかを判断する条件文です。
ビットrが1かどうかはNewAttrとBitRとの論理積で調べることが可能です。ビットrが1の場合は論理積結果がBitRとなりますので、[ e ]の答えは「(NewAttr & BitR) == BitR」となります。
[ g ]は「NewFile及びOldFileの両方にあって」かつ「最終使用日の値が等しい利用者ID」であるかどうかを判断する条件文です。「NewFile及びOldFileの両方にあって」はstrcmp(NewID, OldID)が0であるかどうかで判断可能ですし、「最終使用日の値が等しい利用者ID」はstcmp(NewDate, OldDate)が0であるかどうかで判断可能です。両方が成立することが条件になりますので、[ g ]の答えは「strcmp(NewID, OldID) == 0 && stcmp(NewDate, OldDate) == 0」となります。解いてみた感想
プログラムや回答を考えるのは簡単だったのですが、説明するのが難しかったです・・・。
特定ビットの値を論理積を用いて調べる問題は割とC言語問題で多く出題されていますので、このあたりの知識は身につけておいた方が良いと思います。
★オススメページ★
下記ページから他の回の解説もたどれます。他の回のC言語問題の解き方がわからない場合は是非読んでみてください!
本ページの図・プログラム・問題文について
図やプログラム、問題文はIPA公開の過去問題から引用しています。また図やプログラムに関しては説明に必要な部分に関してのみ加工して使用させていただいております。
出典:平成26年度 秋期 基本情報技術者試験(FE)試験区分 午後 問9