Programmers
Room Tips集
情報処理試験関連 更新[2000.02.14]
Contents
| 1999年秋 問11の解説 [2000.02.14] |
以下は、2000年2月14日発行の「実戦・C/C++言語」の増刊号に掲載された、1999年秋情報処理2種の問題の一つで、私なりの解説を加えてあります。
| 間11 次のCプログラムの説明及びプログラムを読んで,設問1,2に答えよ。 [プログラムの説明]
[プログラム]
設問1 次の記述中の【 】に入れる正しし答えを,解答群の中から選べ。
設問2 次の記述中の【 】に入れる正しい答えを,解答群の中から選べ。
|
※ ここでの記述上の注意。
○ 問題をさっと読む。
参考書などには、まず「設問」を読みなさいと書いてあることが多いで
す。確かに、問題部分には解答に必要の無いことが書いてある場合があります。
もっともなのですが、とりあえず一通り読んで、全体的にどうなっているのか概要をつかむようにしています。
あまり問題とプログラムの理解に時間を取られると、時間内に全部解けなくなります。
軽く読んで、大体の内容を掴むのは、慣れない人には大変かもしれません。その対策は問題集で、数をこなすしか無いでしょう。
○ 設問をじっくり読む
大体の概要を掴んだら設問をじっくり読みます。
特にしっかりプログラムの内容を掴んでいなくても、問題を読むだけで何とか解けてしまう場合もあります。基本的には設問の内容にそってじっくりとコードを追って解答していきます。
○ 実際の解答
設問1
入力文字列と1行の最大文字数が次の値のとき,21行目は【 a 】回実行される。また,プログラムが終了したときの変数posの値は【 b 】である。入力文字列 [AAAA△BBBBB△CCC△DDDD△EEE△FFF\0]
1行の文字数: 18
まずaの方。21行目は何回実行されるのでしょうか?
21行目はelseブロックの中にあり、その上に対応するif文がありそれを、whileで囲んでいるだけの構造です。
このwhile文は何かを考えると、str[i] != '\0' で、iはwhileに入る手前で、0になっていて、while文の最後でiを加算していて、その他でiの値をいじっていないわけですから、入力文字列を先頭0番目から\0を発見する最後まで回るわけです。
よってwhileは入力文字数回まわるのです。
if文を見てみると、ブランクの場合に入るわけですから、elseブロックには「ブランクではない文字数(\0はループから抜けるので含まない)」回入るわけです。
さぁ上記入力文字列のブランク以外を数えましょう。22回ですね。
aの答えは22 (ク)です。
次にbの方。
posのプログラム終了時の値を答えるのですが、このプログラムの処理は大まかに27行目で分断されています。
具体的には前半で入力文字列を単語単位に2次元配列wordにつめておき、後半で、wordを使って、仕様通りに最大文字数以内で単語を出力させているわけです。
まずwhileを見ると、(i<=idx)となっています。
iの値はこの問題の解答であるposと一緒にwhileの前でクリアされていますので、とりあえず置いておいて、idxは何かを考えると、上のwhileに入る直前でクリアし、上のifでインクリメント(加算)しています。
ということは、ブランクの数になるわけで、数えると5個あり、意味的には「単語の数の最大インデックス(個数-1)」ということになります。
だから下のwhileは単語の数分回るのです。
さてaの時と同様、「posが何か」を考えましょう。なんと上のif文の中でクリアしています。
このif文はなんでしょうか?if ((pos + leng[i]) > max) {
posにleng[i]を足した値がmaxより大きい場合?!!
maxは最大文字数なので、18が指定されています。lengはintの配列で、上のループを見ると、どうやらブランクが発見された場合に、単語の長さを代入しているようなので、どうやら「各単語の長さ」が入っているようです。初めてこのif文が実行されるときを「シミュレート」してみると、
if (( 最初は0 + 最初の単語AAAAの長さ4 ) > 18 )
でこのif文には入らないことが分かります。
このようにして、どんどんシミュレートしていけばいつか答えが出るのでしょうが、それでは芸が無いし、問題の主旨にも反しているので、ifの次を見ましょう。
buffのposの位置にi番目の単語をコピーしています。(35行)
posにコピーした単語の長さを加えています。(36行)
buffのposの位置にブランクを代入しています。(37行)
i++だから単語のインデックスをインクリメントです。37行のブランク分
進めたわけです。(38行)
ここでbuffのpos位置(buff[pos])がでてきたので、buffが何か考えます。31と32、41と42行目で表示しています。ということは、buffは出力文字列1行分であることがわかります。ということは、posは、「出力用の文字列に値を詰めていくためのポジション」であることが分かってきます。
ということは、最後にposが出てくる41行目を見てみると、
buff[pos-1] = '\0';
「最後の出力行の終端文字の位置+1」が答えです。
さぁまたここで数えます。最後の文字列はどうなっているのでしょう。
ここでもう一度問題を読み返します。問題文を読んで設問の入力文字列から出力文字列を考えれば、AAAA△BBBBB△CCC\0
DDDD△EEE△FFF\0となるはずです。
最後の行(2行目)の\0の位置(インデックス)はインデックスは0から始まるので12です。
pos - 1 = 12 だから pos=13 よってbの答えはオです。
設問2
「先頭の文字はそのまま出力」したいわけで、上のループに入ってしまうと、スペースは区切りとして処理されるわけですから、まずいわけです。
そこで上のループの前に以下の文が入るわけです。
α while (str[i] == ' '){
word[idx][cnt] = str[i];
【 c 】
【 d 】
}strがブランクの間だけ回るようになっているのだから、先頭の単語(word[idx])に入力文字列の先頭のブランクを詰めることになります。
Cとdに入るものは、おのずと分かりますね。何、わからない?それでは強引に解いてしまいましょう。
wordは下のwhileで出力文字を作成するための、単語です。
最初はi = idx = cnt = 0;ですから、
word[0][0] = str[0];
日本語で書くと最初の単語の0番目の文字 = 入力文字列の0番目の文字
となります。仮にブランクが5つ入っていたとします
△△△△△AAAA△BB....
word[0]に1文字ずつstrの先頭のブランクを代入することをループを使わないで考えると
word[idx][0] = str[0];
word[idx][1] = str[1];
word[idx][2] = str[2];
word[idx][3] = str[3];
word[idx][4] = str[4];
word[idx]とstrの添え字が一つずつ加算されてますね。
これをループで実現するわけですから、cntとiをそれぞれ1ずつインクリメントしてやればよい訳です。
よって答えはアとエです。(添え字:配列のインデックスのこと。str[i]の添え字はi。)
--------------------------------------------
余談ですが、αの部分は
for(i=0,cnt=0;str[i]==' ';i++,cnt++)
word[idx][cnt] = str[i];
と書く方が私は好きです。これでは試験の問題になり難いのでしょうけど。
--------------------------------------------
つぎに、途中のブランクが複数あったら一つにまとめる話。
β while(str[ 【 e 】] == ' ')
i++;
これを18行目に挿入するわけです。
該当位置が含まれるifブロックは何の処理でしたっけ?
そうです。「区切りを見つけた場合にいままで値を代入した単語(word)の
代入を終わらせて、次の単語の代入準備をする」です。
出力文字列の単語と単語の間にブランクを入れる処理は下のループ以降で
やっていますので、上のループでは途中に出てきたブランクは無視する(
wordに代入しない)ようにしなくてはなりません。
βの部分が無い元の状態では、ブランクが2個続いていたとき、if文で次
のwordの準備をした後、ループの先頭に戻って、次のブランクでまたif文
に入ってしまい、まだword[idx]に何も代入されていないのに、次のword
の準備をしていしまったら、空のword[idx]が作られてしまいます。(そ
のままだと、下のループでブランクが2つ出力されます)
よって、βの役割は、ブランクが複数続いた場合に無視するようにすれば
よいわけです。これで分かったことと思います
が、やはり分からなかった人のために、もう少し説明すると、
iは入力文字列の位置を示す値ですから、wordに代入しないでi++とするこ
とでその位置のstrの値を無視することになります。だからβのwhileの中
身のi++は、ブランクを無視しているのです。さてどういうときに無視す
るのでしょう。
2つ目以降のブランクを無視するわけで、今現在の文字str[i]にはif文に
入って来たのだから、絶対にブランクが入っているわけです。
・今ブランク
・ブランクが続く => 今ブランクで、次もブランク
ということですから、
while(次もブランクだったら)
while(str[ 【 e 】] == ' ')は、次の文字をチェックしてやればよい
のです。
だから答えは i+1 カです。
[TOPへもどる] [Soft Page TOPへもどる] [ProgramerS Room Topへ] [このページのTop]