HOME»基本情報技術者平成26年秋期問題»午後問9
基本情報技術者過去問題 平成26年秋期 午後問9
⇄問題文と設問を画面2分割で開く⇱問題PDF問9 ソフトウェア開発(C)
次のCプログラムの説明及びプログラムを読んで,設問1,2に答えよ。
B社では,セキュリティ管理のために,システムファイルから定期的に,システムの運用・保守用の利用者ID一覧を作成し,ファイルで保管している。
これらの利用者IDに付加できる特権には,システムファイルの更新などができるシステム特権(以下,特権Sという)及びバックアップ作業などのために全てのファイルを参照できるオペレーション特権(以下,特権0という)の2種類がある。
B社では,セキュリティ管理強化の一環で,利用者IDの追加・削除や特権の付加・解除が,申請に基づいて正しくシステムに反映されているかどうかを検証することになった。そのために,最新及び1世代前の利用者ID一覧を比較して,この間の利用者ID及び特権の登録内容の差異を印字するプログラムを作成する。
〔プログラムの説明〕
B社では,セキュリティ管理のために,システムファイルから定期的に,システムの運用・保守用の利用者ID一覧を作成し,ファイルで保管している。
これらの利用者IDに付加できる特権には,システムファイルの更新などができるシステム特権(以下,特権Sという)及びバックアップ作業などのために全てのファイルを参照できるオペレーション特権(以下,特権0という)の2種類がある。
B社では,セキュリティ管理強化の一環で,利用者IDの追加・削除や特権の付加・解除が,申請に基づいて正しくシステムに反映されているかどうかを検証することになった。そのために,最新及び1世代前の利用者ID一覧を比較して,この間の利用者ID及び特権の登録内容の差異を印字するプログラムを作成する。
〔プログラムの説明〕
- 最新の利用者ID一覧をファイル NewFile から,1世代前の利用者ID一覧をファイル OldFile から,それぞれ読み込む。レコードは利用者IDの昇順に整列されている。
- 1レコードは,利用者ID(1~8桁),利用者名(1~10桁),属性(1桁)及び最終使用日(8桁)の4項目から成る。各項目は,空白文字で区切られている。
- 利用者ID及び利用者名は,英数字から成る文字列である。
- 属性は,次に示す内容の8ビット長のビット列である。
- 上位4ビット: 固定値0100
- ビットs: 特権Sが付加されていれば1,付加されていなければ0
- ビットo: 特権Oが付加されていれば1,付加されていなければ0
- ビットg及びr: その他の属性
- 最終使用日は,数字から成る文字列で,その利用者IDで最後にログインした年月日を表す。登録後,一度もログインしていない場合は,全桁が"0"である。
- 利用者ID及び特権の登録内容の差異は,次のように印字する。
- NewFile 中にあって OldFile 中にない利用者IDの場合
利用者ID,利用者名の後に"利用者ID追加"と印字する。この利用者IDに特権Sが付加されていれば"特権S付加",特権Oが付加されていれば"特権O付加"を追加印字する。 - OldFile 中にあって NewFile 中にない利用者IDの場合
利用者ID,利用者名の後に"利用者ID削除"と印字する。この利用者IDに特権Sが付加されていれば"特権S解除",特権Oが付加されていれば"特権O解除"を追加印字する。 - NewFile 及び OldFile の両方にあり,特権Sと特権Oの少なくとも一方の付加状況が変わった利用者IDの場合
利用者ID,利用者名の後に"特権S付加","特権S解除","特権O付加","特権O解除"の該当する全てを印字する。
- NewFile 中にあって OldFile 中にない利用者IDの場合
- 入力ファイル NewFile 及び OldFile のデータ例を図1に,図1のデータ例を用いた実行結果を図2に,それぞれ示す。
- ライブラリ関数 strcmp(s1,s2)は,文字列 s1 と s2 を比較し,s1< s2 のとき負の値を,s1=s2 のとき0を,s1>s2 のとき正の値を,それぞれ返す。
設問1
プログラム中の に入れる正しい答えを,解答群の中から選べ。
a に関する解答群
- (NewEof != EOF) && (OldEof != EOF)
- (NewEof != EOF) || (OldEof != EOF)
- NewEof != OldEof
- NewEof == OldEof
b に関する解答群
- ((NewAttr & OldAttr) & (BitS+BitO)) != 0x00
- ((NewAttr | OldAttr) & (BitS+BitO)) != 0x00
- (NewAttr & (BitS+BitO)) != (OldAttr & (BitS+BitO))
- (NewAttr l (BitS+BitO)) != (OldAttr | (BitS+BitO))
c に関する解答群
- ReadNewRecord();
- ReadNewRecord();
ReadOldRecord(); - ReadOldRecord();
d に関する解答群
- (NewAttr & (BitS+BitO)) != 0x00
- NewAttr > OldAttr
- strcmp(NewID,OldID) < 0
- strcmp(NewID,OldID) > 0
解答選択欄
- a:
- b:
- c:
- d:
解答
- a=イ
- b=ウ
- c=イ
- d=ウ
解説
〔aについて〕
〔プログラムの説明〕の説明より、利用者IDの昇順に整列された NewFile と OldFile の突合せ処理によって差異を確認することがわかるので、どちらも最終行まで読む必要があります。よって、プログラムの終了条件としては、NewFile と OldFile のどちらも最終行まで読込んだことになります。逆に、while文の条件式にはループの継続条件を記述するので、「NewFileが最終行ではない」または「OldFileが最終行ではない」ことを示す式が入ります。
ReadNewRecord とReadOldRecord では、fscanf関数でファイルから書式付きで1行を読み込んだ後、feof関数の結果で分岐させています。feof関数はファイルが終端に達しているときには0以外を、終端に達していないときには0を返します。feof関数が0以外を返したときに、NewEof 及び OldEof に EOF を代入していることから、NewEof 及び OldEof の値が EOF であればファイルの終端に達していると判定できます。
両方のファイルが終端に達するまでループ内の処理を繰り返す必要があるので、継続条件式としては (NewEof != EOF) || (OldEof != EOF) が適切です。
∴a=イ:(NewEof != EOF) || (OldEof != EOF)
〔bについて〕
strcmp関数の結果が0ということは2つの利用者IDが一致しているということです。このとき行う処理は〔プログラムの説明〕(3)③の「NewFile 及び OldFile の両方にあり,特権Sと特権Oの少なくとも一方の付加状況が変わった利用者IDの場合」処理になります。if文で真となるときに印字処理を行っているので、条件式[b]には「特権Sと特権Oの少なくとも一方の付加状況が変わった」ことを判定するための式が入ります。
2つの利用者IDの属性情報は NewAttr 及び OldAttr に格納されているので、それぞれから特権Sと特権Oを表す位置のビットを取り出した後、双方を比較すれば付加状況が変化したかどうかがわかります。特権Sのビット位置はBitS=0x08(0000 1000)、特権Oのビット位置はBitO=0x04(0000 0100)ですので、これを"+"で合成した0x12(0000 1100)をビットマスクとしてAND演算を行えば、該当するビットだけを取り出せます。こうして取り出した2つのビット列を比較し、値が異なれば印字処理に進むことになります。
∴b=ウ:(NewAttr & (BitS+BitO)) != (OldAttr & (BitS+BitO))
〔cについて〕
〔プログラム〕中の if (strcmp(NewId, OldID) == 0) 内の処理で、NewFile と OldFile の両方のレコードに対して処理を実施しています。1つのファイルに同じ利用者IDの行が含まれていることはないので、両方のファイルについて新しいレコード(次行)を読み込む必要があります。したがって「イ」が正解です。
∴c=イ
〔dについて〕
この条件式が真となる場合には"利用者ID 追加"を印字し、偽となる場合には"利用者ID 削除"を印字しています。これは〔プログラムの説明〕(3)の①②の処理に該当し、"利用者ID 追加"と印字するのは「NewFile 中にあって OldFile 中にない利用者IDの場合」です。
利用者IDの昇順に整列されたファイルの先頭から1行ずつ読み込むことを考えると、①2つのIDが一致、②NewFile のIDが OldFile のIDよりも小さい、③NewFile のIDが OldFile のIDよりも大きい、という3つのケースが存在することがわかります。このうち NewID が OldID よりも小さいケースでは、OldFile からは NewID があるべき位置を越えて次のIDを読み込んでいるということなので、OldFile 中には NewID を持つレコードが存在しないと判断できます。strcmp関数は、文字列 s1 と s2 を比較し,s1< s2 のとき負の値を返すので、strcmp(NewID, OldID) が0未満の値を返せば、その NewID は OldFile 中にないと判断できます。
「ア」「イ」は属性の値で判定しているので不適切、「エ」は当該 OldID が NewFile 中にない場合に真となる条件式なので不適切です。
∴d=ウ:strcmp(NewID,OldID) < 0
〔プログラムの説明〕の説明より、利用者IDの昇順に整列された NewFile と OldFile の突合せ処理によって差異を確認することがわかるので、どちらも最終行まで読む必要があります。よって、プログラムの終了条件としては、NewFile と OldFile のどちらも最終行まで読込んだことになります。逆に、while文の条件式にはループの継続条件を記述するので、「NewFileが最終行ではない」または「OldFileが最終行ではない」ことを示す式が入ります。
ReadNewRecord とReadOldRecord では、fscanf関数でファイルから書式付きで1行を読み込んだ後、feof関数の結果で分岐させています。feof関数はファイルが終端に達しているときには0以外を、終端に達していないときには0を返します。feof関数が0以外を返したときに、NewEof 及び OldEof に EOF を代入していることから、NewEof 及び OldEof の値が EOF であればファイルの終端に達していると判定できます。
両方のファイルが終端に達するまでループ内の処理を繰り返す必要があるので、継続条件式としては (NewEof != EOF) || (OldEof != EOF) が適切です。
∴a=イ:(NewEof != EOF) || (OldEof != EOF)
〔bについて〕
strcmp関数の結果が0ということは2つの利用者IDが一致しているということです。このとき行う処理は〔プログラムの説明〕(3)③の「NewFile 及び OldFile の両方にあり,特権Sと特権Oの少なくとも一方の付加状況が変わった利用者IDの場合」処理になります。if文で真となるときに印字処理を行っているので、条件式[b]には「特権Sと特権Oの少なくとも一方の付加状況が変わった」ことを判定するための式が入ります。
2つの利用者IDの属性情報は NewAttr 及び OldAttr に格納されているので、それぞれから特権Sと特権Oを表す位置のビットを取り出した後、双方を比較すれば付加状況が変化したかどうかがわかります。特権Sのビット位置はBitS=0x08(0000 1000)、特権Oのビット位置はBitO=0x04(0000 0100)ですので、これを"+"で合成した0x12(0000 1100)をビットマスクとしてAND演算を行えば、該当するビットだけを取り出せます。こうして取り出した2つのビット列を比較し、値が異なれば印字処理に進むことになります。
∴b=ウ:(NewAttr & (BitS+BitO)) != (OldAttr & (BitS+BitO))
〔cについて〕
〔プログラム〕中の if (strcmp(NewId, OldID) == 0) 内の処理で、NewFile と OldFile の両方のレコードに対して処理を実施しています。1つのファイルに同じ利用者IDの行が含まれていることはないので、両方のファイルについて新しいレコード(次行)を読み込む必要があります。したがって「イ」が正解です。
∴c=イ
〔dについて〕
この条件式が真となる場合には"利用者ID 追加"を印字し、偽となる場合には"利用者ID 削除"を印字しています。これは〔プログラムの説明〕(3)の①②の処理に該当し、"利用者ID 追加"と印字するのは「NewFile 中にあって OldFile 中にない利用者IDの場合」です。
利用者IDの昇順に整列されたファイルの先頭から1行ずつ読み込むことを考えると、①2つのIDが一致、②NewFile のIDが OldFile のIDよりも小さい、③NewFile のIDが OldFile のIDよりも大きい、という3つのケースが存在することがわかります。このうち NewID が OldID よりも小さいケースでは、OldFile からは NewID があるべき位置を越えて次のIDを読み込んでいるということなので、OldFile 中には NewID を持つレコードが存在しないと判断できます。strcmp関数は、文字列 s1 と s2 を比較し,s1< s2 のとき負の値を返すので、strcmp(NewID, OldID) が0未満の値を返せば、その NewID は OldFile 中にないと判断できます。
「ア」「イ」は属性の値で判定しているので不適切、「エ」は当該 OldID が NewFile 中にない場合に真となる条件式なので不適切です。
∴d=ウ:strcmp(NewID,OldID) < 0
設問2
次の記述中の に入れる正しい答えを,解答群の中から選べ。
利用者IDが有効に使用されているかどうかを検証するために,一定期間未使用,又は現在使用不可の利用者ID一覧を印字するプログラムを作成する。
利用者IDが有効に使用されているかどうかを検証するために,一定期間未使用,又は現在使用不可の利用者ID一覧を印字するプログラムを作成する。
- 最新の利用者ID一覧をファイル NewFile から,一定期間前の世代の利用者ID一覧をファイル OldFile から,それぞれ読み込む。
- 次の①,②の少なくとも一方に該当する利用者IDについて,利用者ID,利用者名の後に,①に該当する場合は"現在使用不可"を,②に該当する場合は"期間中未使用"を印字する。
- NewFile 中にあって,属性の ビットr が1である利用者ID
ここで,属性の ビットr は,利用者IDが使用可能なら0,使用不可なら1である。 - NewFile 及び OldFile の両方にあって,最終使用日の値が等しい利用者ID(全桁が"0"同士で等しい場合を含む)
- NewFile 中にあって,属性の ビットr が1である利用者ID
- 図3に,図1のデータ例を用いた実行結果を示す。
e,f に関する解答群
- (NewAttr & BitR) != (OldAttr & BitR)
- (NewAttr & BitR) == BitR
- strcmp(NewDate,OldDate) == 0
- strcmp(NewID,OldID) == 0
- strcmp(NewID,OldID) == 0 && (NewAttr & BitR) == BitR
- strcmp(NewID,OldID) == 0 && strcmp(NewDate,OldDate) == 0
解答選択欄
- e:
- f:
解答
- e=イ
- f=カ
解説
利用者IDを出力する条件は次の2つです。
〔eについて〕
if文が真のときに"現在使用不可"を印字しているので、①のケースを判定する条件式が入ります。
現在読み込んでいる NewFile 内のレコードから属性のビットrを取得するには、BitR をビットマスクとして NewAttr とAND演算を行い、その結果が BitR と一致するかどうかを確認することになります(0より大きいことを確認してもよさそうですが)。
なお「ア」は、NewAttr と OldAttr のビットrが異なっていれば真となってしまうので誤りです。これだと、NewAttr のビットr=0、NewAttr のビットr=1 でも真となってしまいます。
∴e=イ:(NewAttr & BitR) == BitR
〔fについて〕
if文が真のときに"期間中未使用"を印字しているので、②のケースを判定する条件式が入ります。当該IDが NewFile 及び OldFile の両方にあることを strcmp(NewID, OldID) == 0 で確認し、かつ、当該IDの最終使用日が NewFile と OldFile で等しいことを strcmp(NewDate,OldDate) == 0 で確認する「カ」の条件式が適切です。
「ウ」は最終使用日だけで判断しているので誤り、「エ」は利用者IDだけで判断しているので誤り、「オ」は利用者IDとビットrの組で判断しているので誤りです。
∴f=カ:strcmp(NewID,OldID) == 0 && strcmp(NewDate,OldDate) == 0
- NewFile 中にあって,属性の ビットr が1である利用者ID
- NewFile 及び OldFile の両方にあって,最終使用日の値が等しい利用者ID
〔eについて〕
if文が真のときに"現在使用不可"を印字しているので、①のケースを判定する条件式が入ります。
現在読み込んでいる NewFile 内のレコードから属性のビットrを取得するには、BitR をビットマスクとして NewAttr とAND演算を行い、その結果が BitR と一致するかどうかを確認することになります(0より大きいことを確認してもよさそうですが)。
なお「ア」は、NewAttr と OldAttr のビットrが異なっていれば真となってしまうので誤りです。これだと、NewAttr のビットr=0、NewAttr のビットr=1 でも真となってしまいます。
∴e=イ:(NewAttr & BitR) == BitR
〔fについて〕
if文が真のときに"期間中未使用"を印字しているので、②のケースを判定する条件式が入ります。当該IDが NewFile 及び OldFile の両方にあることを strcmp(NewID, OldID) == 0 で確認し、かつ、当該IDの最終使用日が NewFile と OldFile で等しいことを strcmp(NewDate,OldDate) == 0 で確認する「カ」の条件式が適切です。
「ウ」は最終使用日だけで判断しているので誤り、「エ」は利用者IDだけで判断しているので誤り、「オ」は利用者IDとビットrの組で判断しているので誤りです。
∴f=カ:strcmp(NewID,OldID) == 0 && strcmp(NewDate,OldDate) == 0