平成30年度春期午後のC言語問題である問9の私の解き方・考え方について解説していきます。
問題
IPAの公式サイトで公開されています。このページでは問9についての解説を行います。
https://www.jitec.ipa.go.jp/1_04hanni_sukiru/mondai_kaitou_2018h30_1/2018h30h_fe_pm_qs.pdf
設問1
まずは問題を読んでいきましょう。
ポイントは下記あたりでしょうか。
- 簡易集計プログラム
- キー項目で整列済み
- キー項目ごとに、その件数や数値項目の合計を求める
- ↑これを集計ファイルに書き出す
ここで具体的にキー項目と数値項目がなんであるかを考えて見ましょう。図1のデータを集計した結果が図2なので、キー項目は品番、数値項目は金額であることがわかります。
さらに問題を読み進めましょう。次はプログラム1についての説明があります。
ここでレコード先頭からのキー項目の位置を表すkeyPos、キー項目の桁数を表すkeyLen、先頭からの数値項目の位置を表すvaluePos、数値項目の桁数を表すvalueLenの説明が行われています。図に表すと↓みたいな感じですね。こんな感じでどんどん図に追記したり絵を描いたりして問題読みながら理解を深めましょう。
またプログラム中に出てくる関数の説明もしてくれています。親切な問題ですね!
実際のプログラムは下記です。
スポンサーリンク
設問1の考え方
まず[ a ]はinFileやoutFile変数が何型として宣言されているかの問いになります。
プログラム中の黒線で囲った部分を見ればすぐ分かりますね。outFile、inFileにはfopen()の戻り値が代入されています。fopen()の戻り値の型はFILE*ですので、[ a ]の答えは「FILE」となります。
[ b ]と[ c ]についてはもう少しプログラムの意味を理解して解いてやる必要があります。まずプログラムを追ってどういう処理をしているかを見てみましょう。
まず青枠で囲った部分では
- 入力ファイルの1行目を読み込んで1行分をinBufにコピー
- inBufの先頭からkeyPos分シフトしたアドレスよりkeyLen文字分をkeyにコピー。key Posは行の先頭からのキー項目の位置を表し、keyLenはキー項目の桁数を表すので、要はキー項目名をkeyにコピーしている
- countを1にセット。この変数はキー項目の件数と予想
- valueに数値項目を代入(基本的にキー項目と同じ考え方)
を行なっています。
入力ファイルの一行目を読み込んだ時の処理ですね。
ピンク枠の中も青枠と同様の処理を行なっています(countに関しての処理はない)。が再度fgets()関数を行なっていますので、次の行に対して同じような処理を行なっていると考えられます。
- 次の行を一行分読み込んでinBufにコピー
- inKeyに次の行のキー項目名をコピー
- inValueに次の行の数値項目を代入
続いて緑枠の中を見てみましょう。
まずkeyとinKeyの比較を行なっています。ここまでのプログラムよりある行のキー項目とその行のキー項目の比較です。
緑枠はこの二つが異なる時の処理となります(strcmpは二つの文字列が同じ時に0を返す)。
この問題では入力ファイルはキー項目で整列済みという前提があります。なのでここが実行されるということは、このキー項目はもう今後出てこない、ということになります。なのでこのキー項目についての情報をfprintf()で出力ファイルに書き出しています。さらに、キー項目が異なるということはこの行から新しいキー項目が始まったということなのでcountを1に初期化し、キー項目をkeyにコピーしています。
- keyとinKeyの比較
- 異なる時はここまでのkeyの情報をファイルに書き出し
- さらに新たなkeyとしてkeyにinKeyを代入
- countを初期化
- valueをinValueで上書き
オレンジ枠は[ b ]の答えとなります。ここは緑枠内のkeyとinKeyの比較が同じ場合に実行される部分です。
keyとinKeyが同じということは、keyを設定した行と先ほどピンク枠で取得した行とでキー項目が同じということです。
一方、プログラムの目的は各キー項目毎の件数と数値項目の合計を算出してファイルに書き出すことですので、オレンジ枠内では
- キー項目keyの件数をカウントアップ
- 数値項目をinKeyの数値項目に加算
が必要になります。この処理が[ b ]となります。C言語で考えれば
- count++;
- inValu += value;
となりますので、この2行の処理が[ b ]の答えとなります。
最後に赤枠内を見てみましょう。この赤枠内の処理が[ c ]の答えとなります。
赤枠が実行される時は、ピンク枠内のfgets()関数でNULLが返ってきたとき、すなわち、もう入力ファイル内の読み取る行が無い時となります。
この時に必要になる処理は何なのか考えましょう。
もう入力ファイル内の読み取る行がないということは、最後のkeyに対する集計が完了したときと考えることができます。
しかし、このkeyに対する集計の情報はまだ出力ファイルに書き出しされていません。
一つ前のfgets()でNULL以外が返ってきた時でも、緑枠が実行されていれば一つ前のkeyに対する情報は出力ファイルに書き出されますが、最後のkeyに対する情報は書き出しされていないことになります。オレンジ枠が実行されていたとしてもここではkeyに対するcountとvalueの値を更新するだけで出力ファイルに書き出しは行なっていません。
このまま終わると最後のキー項目の情報がファイルに書き出されないままプログラムが終了することになってしまいます。ですので、この[ c ]では出力ファイルに現在のkeyの情報を書き出してやる必要があります。こんな感じで論理的に考えていくと、答えは
fprintf(outFile, format, key, count, value);
であると導き出せると思います。
設問2
今度は時間帯毎の合計金額を求めそれを*を積み重ねて描写する横グラフで表現するプログラムを作成する問題になります。
色々説明書いてありますが、正直この設問2に関しては問題文読まなくても解ける問題だと思います。
設問2の考え方
この問題は要するに、
graph[25 – 25 * value / valueMax]
の部分において、①算術演算であふれ、②算術演算でゼロ除算、③配列の定義外の要素位置を参照するの3つが起こりうる可能性のあるvalueとvalueMaxの組み合わせを選択肢から選ぶ問題です。ですので、問題をじっくり読まなくても、①②③がどういう場合に起こりうるかを考えれば溶けてしまいます。
選択肢は下記のようになっています。
①の算術演算でのあふれについては、まずvalueやvalueMaxがlong型であることに注目し、long型が取りうる値を超える計算結果になるところがないかを考えれば解けます。しかもlong型が取りうる値の範囲も問題文に書いてくれています。
ここで「25 * value」に注目すると、valueが「longの最大値/25」を超える場合にあふれが発生することになります。そう考えると、選択肢の中ではvalueが100,000,000の場合のみあふれが発生することになります。ですので、valueが100,000,000のカが答えとなります。
②は言葉の通りゼロで除算する場合に起こります。ですのでvalueMaxが0の時であり、答えはアしかありえません。ゼロ除算は数学やプログラムの世界ではご法度です。このことをは覚えておきましょう。
③はまず配列の要素数がいくつかを見る必要があります。これはgraphの変数宣言時のプログラムを見てやれば要素数は25であることがわかります。ですので、25 * value / valueMaxの部分が負の値になってしまうと、25 – 25 * (負の値)となって25を超える数字となり、要素外を参照してしまうことになります。ですので、25 * value / valueMaxが負の値になるケースを選択肢から選べば答えが導き出せます。マイナスになるのはイだけですね。
スポンサーリンク
問題を解いた感想
正直めちゃめちゃ簡単でした。[ b ]と[ c ]以外はファイル扱うプログラム書いたことのある人で、桁あふれ等の知識がある人であれば問題文読まなくても正確に回答出来ると思います。特に[ a ]に関してはfopen()使ったことある人なら即答できますね。[ b ]と[ c ]に関しても作ろうとしているプログラムを理解していればすぐに答えを導き出せると思います。この問題であれば5分あれば解けてしまいますね。サービス問題だと思います。
解いていてポイントだと思ったのは、
- 問題文で重要そうな部分は図やプログラムにどんどん追記する
くらいですね。
★オススメページ★
下記ページから他の回の解説もたどれます。他の回のC言語問題の解き方がわからない場合は是非読んでみてください!
本ページの図・プログラム・問題文について
図やプログラム、問題文はIPA公開の過去問題から引用しています。また図やプログラムに関しては説明に必要な部分に関してのみ加工して使用させていただいております。
出典:平成30年度 春期 基本情報技術者試験(FE)試験区分 午後 問9