Comments
Description
Transcript
誤答例
情報処理 II 試験問題 (2011 年 2 月 7 日) の誤答例 (2 月 14 日改訂) タイプライタ体でない「;」は誤答の区切り, 「⇒」以降は添削例, 「//」以降は村川のコメントである. 2 • (1) -1,0,1,2 // 2 は,「ループ終了時の (ループ内の処理で使用されない) 値」である. • (1) i+1 // i=i+1 と勘違いした? • (2) i*3 // for(i=2;i<100;i*3) は,文法的には問題ないが,i の値が更新されず無限ループに 陥る. • (2) i=i^3 // ビット単位の排他的論理和の演算をするので,i の値は 2,1,2,1,... となる. • (3) (1,1),(2,1),(3,1),(1,2),(2,2),(3,2),(1,3),(2,3),(3,3) // この解答になる 2 重 ループは,for(j=1;j<=3;j++) for(i=1;i<=3;i++) である. • (3) (1,1),(2,2),(3,3) // 「j の値は変わるが i の値は変わらない」という状況がある点に注 意して,問題文(と正解)を見直してほしい. • (4) i;j ≦ 2;j++ // プログラムコードを書くべきところで「≦」は間違い. • (4) i,j<3,j++ // for のカッコの中には,; が (コメント,文字列リテラルを除いて) ちょうど 2 つ必要となる. • (4) 0;i<=j;j++ // これでは,i の値が変わった直後に j の値は必ず 0 となるため,パターンの 最後の 2 つは「(1,2),(2,2)」にならない.j の初期化が 1 でも同様. • (4) j=i;j<2;j++ // 初期化が j=j=i となる (一つの式で j に二度代入するのは良くない.リ pp.174–176). • (5) FILE; スタック; ストリーム; 配列 // 2 番目以降の (5) に当てはめると,おかしくなる. • (6) char; char *; char の配列; 文字列; FILE *; ポインタ // ライブラリ関数 fgetc の戻り値 の型にしなければならない. • (7) <stdio.h> // ここは関数名を書かないといけない. • (7) fgetc; malloc; scanf // 「fp は... (7) を呼び出し,その戻り値を保持している」に 合わない. • (7) 引数 // 「ライブラリ関数の引数を呼び出し」は,おかしい. • (7) FILE *fopen(char *path, char *mode); // 関数名だけを書く. • (8) ファイルポインタが示す,ファイルの中の値を取り出す // 「1 バイト (または 1 文字) の値」 としなければならない. • (8) 1 列を読み込む; 1 行ずつ読み込む // fgetc は,バイト単位の処理となる. • (8) ファイルの中身を 1 文字ずつチェックしている; ファイルの文字を 1 文字ずつ検索している // 「チェック」や「検索」ではなく,「読み出し」である. • (8) ファイルの先頭から 1 文字ずつ読み出して,その値をファイルポインタに返している // 1 文 字読み出すと,fp が指し示す FILE オブジェクトの中身は少々変わるかもしれないが,fp の値 そのもの (どこを指し示すか) は変化しない. • (8) ファイルポインタの 1 バイトを読み出す // 読み出す対象を間違っている. 1 • (8) 文字列のはじめから 1 バイトずつ読み出す // fgetc と while ループを組み合わせて使うの では,文字列は出てこない. • (8) 停止判定をするために使用されている // 「読み出す」という重要な情報が抜けている. • (8) 変数 c へファイルの値を代入する // 「ファイルの値」では通じない. • (8) EOF と該当するまで // この他にも, (8) の直後の句点(.)を読点(,)と勘違いし たと思われる答案が見られた. • (8) 処理対象; 処理内容 // 関数形式マクロと勘違いした? 「処理内容を書く」を誤解した? • (9) EOF; -1 // 「EOF(または-1) に達して c に EOF が代入される」は,おかしい. • (9) ナル文字; ヌル文字; NULL 文字; 終端文字; 終端記号 // ストリームなので,そんな文字や記 号があるわけではない.第 13 回 (20110117) 参照. • (9) \n // 改行文字とファイルの終わりは違う.一般に,一つのテキストファイルには複数の改 行文字がある. • (9) NULL; 終端のアドレス // fgetc を使用する限り,戻り値がポインタ (アドレス) になること はない. • (9) ファイルの文末; ファイルの最終行; ファイルの最後の文字 // ピントがずれている. • (9) ファイルの終端の一つ後ろ // 「ファイルの終端」で十分. 3 (複数の答案に見られた記述) • 関数 floatbit は void 型の関数である // 「戻り値の型が void」である.floatbit そのもの の型は,「関数型」をキーワードに自習してほしい. • 6 行目はプロトタイプ宣言であり // 関数定義の一部である.プロトタイプ宣言であれば,閉じ カッコの後に; が来なければならない. • q の初期値は,図 1 の 0x0999 番地を指している // 0x1000 から 1 を引いたら 0x0fff(また は 0xfff) である.それと,図 1 には num のことをまったく書いていないので,「num が図 1 の 0x1000 番地から 0x1003 番地を占めるとき」といった断り書きは,入れておかないといけない. • sizeof は引数の占めるメモリ領域を返すライブラリ関数である // sizeof は,演算子である (第 4 回 (20101101)). • q に終了アドレスの一つ前のアドレスを代入し,p に開始アドレスを代入している // 「開始ア ドレス」「終了アドレス」が何を指すのか分からない.ここは,13–26 行目が p をループカウン タとする for ループであることに注意し,p の初期値,反復を終える値がそれぞれ何なのかを説 明するのがよい. • p の中身を c に代入している // これは c = *p よりもむしろ c = p と解釈されてしまう.「参 照」もしくは「指し示す」という言葉が使えるようになろう. • b=10000000 と初期化する // 一千万に見える.「2 進数で表すと」といった断りがほしい. • b が 0 以下になった時点で for ループを終了する // 構文的 (論理的) にはそのとおりだが,読 解・論述としては不十分.b は符号なしなので, 「0 以下」ではなく「0」と書かないといけない. 2 • b と c のビットが合致すれば // それだと if (c == b) である. • c かつ b であった場合 // それは if (c && b) である. • b に 1 を代入し,1 を左に 7 回シフトさせて // = と << の優先順位に注意すると,b = (1 << 7) であって (b = 1) << 7 ではない. • b の値を半分にし // 整数値としてみると半分になっているが,ここではシフト演算として使用 しているので,「b の値を 1 ビット右にシフトする」のほうが適切である. • *argv[] には文字列が入る // 変数名は argv であり,厳密に言えば argv[0], argv[1], ... が 文字列を指し示す (または空ポインタ定数 NULL と等しい) ポインタとなる.実用上は,argv[0], argv[1], ... は(NULL でなければ)文字列と同一視される. • argv[] という char *型の変数を用いている // 同上.加えて,*argv もしくは argv[0] は, char *型の (変数ではなく) 値となる. • atof により,文字列を float 型の数値に変換し,それを floatbit 関数に渡している // atof の仕様を見直してほしいが (リ p.495),戻り値は double 型である.この値がどこで float 型に 変換されるかというのが,36 行目の関数呼び出しを説明する要所の一つである. • このプログラムは,ある実行環境で,./floatbit -3.5 を実行すると,「-3.5: 11000000 01100000 00000000 00000000」という出力になった. // あまりにも安直な結合,安直な論 述の出だしである. • 2 進数で入力する // しない.「入力は何か」「出力は何か」を理解し,正しい日本語 (かつ正しい 技術表現) で言ったり書いたりできるようになろう. (誤記ほか) • 1 括 ⇒ 一括 • 記込 ⇒ 書き込み // 「記入」か「書き込み」かで混乱したか? • 結課 ⇒ 結果 • 実引き数 ⇒ 実引数 • 単準 ⇒ 単純 • 番値 ⇒ 番地 • 先頭 1 ビットは符合 ⇒ 先頭 1 ビットは符号 • /.floatbit -3.5 ⇒ ./floatbit -3.5 // 「./」と書くことで,カレントディレクトリの floatbit を実行ファイルとして,コマンドを実行することになる. • float bit 関数 ⇒ floatbit 関数 // ファイル名やソースコード中の識別子で,空白がないの に空けるような書き方は,しないように. • ポイント型 ⇒ ポインタ型 • まずドットヘッダを宣言する ⇒ まずヘッダファイルをインクルードする • 自作関数 void // void は予約語の一つであり,関数名 (識別子) として使用できない. (さらにレベルアップを) • 32 bit を 8 bit ごとに分けて出力するプログラムである ⇒ float 型の値を 8 bit ごとに出力す 3 るプログラムである // float 型が 32 bit であることは,プログラムの仕様として書くべきでは なく,実行例から推測できる情報である. • コマンドライン引数を定義している; コマンドライン引数を宣言している ⇒ コマンドライン引 数より値を獲得する • int i を作る ⇒ int 型の変数 i を定義する // 「変数 i を int 型で定義する」という言い方も 聞くが,レジでたまに耳にする「千円でお預かりします」と同様に,美しい日本語ではない. • argv[0] は./floatbit,argv[1] は-3.5,argv[2] は NULL が入れられる ⇒ argv[0] は "./floatbit",argv[1] は"-3.5"となり,argv[2] には NULL が格納される // 文字列を指し 示すポインタが,文字列と同一視されるのは前述のとおり.「3.5」と「"3.5"」を区別しよう. • 文字列を関数 atof で値化し ⇒ 文字列を,関数 atof で double 型の値にし // 文字列の "-3.5",double 型の-3.5,いずれも値である. • atof 関数によって文字列が float 型の数字に変えられて ⇒ atof 関数によって,文字列が double 型の値に変換され • atof を argv[i] として呼び出し,floatbit にしている ⇒ argv[i] を引数として関数 atof を呼び出し,さらに,その戻り値を引数として関数 floatbit を呼び出している • 3–4 行目で,インクルード文 <stdio.h>, <stdlib.h> を宣言している ⇒ 3–4 行目で,ヘッダ ファイル stdio.h, stdlib.h を取り込んでいる // < と > は,インクルード文の構成要素であ り,「stdio.h」「stdlib.h」がヘッダファイルである. • stdio.h をインクルードしたのは,void と printf と sizeof を使えるようにするためである ⇒ stdio.h をインクルードしたのは,ライブラリ関数の printf を使えるようにするためであ る // すでに書いたとおり,void も sizeof も関数ではない.なお,NULL もまた,stdio.h (別 のヘッダファイルでもよい) をインクルードすることで使える定数 (オブジェクト形式マクロ) で ある (リ p.457, リ p.424). • 14–15 行で変数を宣言しているが,変数の宣言は関数のはじめにするという規格もあるので好ま しくない // ブロックの先頭で変数を宣言できる (リ p.222, リ p.113). • floatbit 関数は入れ子構造になっており ⇒ floatbit 関数は入れ子の for ループを持って おり • floatbit 関数の中では,float 型の num,unsigned char 型の*q, *p が変数として使用され ている ⇒ floatbit 関数は,仮引数として float 型の num を持つ.またローカル変数として, unsigned char 型のポインタ q, p を持つ // 仮引数と,関数のブロック内で宣言されている ローカル変数は,分けて記述するのが望ましい. • l.7, l.8 の*q, *p はどちらも正の数の整数である変数 q, p を確保している // 添削できない.最 低限,変数宣言において*は変数名の一部ではなく型名の一部であることを,理解してほしい. • q には (unsigned char *)&num-1 を代入し,p には q+sizeof(float) を代入している // 値 の意味を書かないのでは,それぞれの宣言文を理解し説明したとは言えない. • q に読み出しの終了地点のアドレス,p に読み出しの先頭地点のアドレスを代入する // 「q に終 了アドレスの」から始まる誤答とそれに対する解説を見直してほしい.それと,「読み出しの終 了地点のアドレス」は,q ではなく q+1 ((unsigned char *)&num と等しい) である. 4 • p̸=q; p=p-1 のとき // 条件 → 処理 → 増分 → 条件 → 処理 → 増分 →... (第 3 回 (20101025)) という反復が分かるような説明を書いてほしい. • p の値と q の値が違えば,p を減算する // 同上.実際には,デクリメントしてから,p と q の比 較をする. • c & b が 0 でないとき,if 文が,0 のとき,else 文が実行される // 「else 文」という表現は 自然ではない.if 文は,18–22 行目を占める. • 右に 1 桁ずつずらしていく // 「桁 (digit)」ではなく「ビット (bit)」, 「ずらす」ではなく「シフ トする」. • "\n" (終端文字) を出力する // 一般に,終端文字とは ’\0’ をいう. • 改行文字が入れられている ⇒ 改行を出力する • 浮動小数の値 ⇒ 浮動小数点数 // 「浮動 + 小数点 + 数」という分割をするので,「浮動小数」 はおかしい (または俗語であり,試験の答案には望ましくない). • 今は省略する ⇒ 後述する // こう書くからには,答案の後ろの方で言及していなければならな い (答案はそうしていた). • 簡略の為 ⇒ 簡単のため // 英語では “for simplicity” と書く. 5