中間テストはペーパーテストが 12 点満点(順に 2, 3, 2, 2, 3 点)、
オンラインテストが 8 点満点(4, 4 点)で採点する。
(ただし、最終的な成績の計算にはこの半分 — ペーパーテスト 6点満点、
オンラインテスト 4 点満点 — の割合で用いる。)
期末テストは、もっと難易度は高くなる。
今回はテストであるので、オンラインテストの解答に NG というメッセージがあっても、 再提出する必要はない。
ペーパーとオンラインを合算して、得点率が 7 割未満の者には、 追試験を実施する予定である。詳細は追って連絡する。
オンラインテストでセミコロンの付け忘れなど基本的な文法事項で何度もエラーを出しているようでは、 時間内に課題を仕上げることが非常に困難になる。 文法は“何となく”ではなく、確実に理解しておく必要がある。
以下のプログラムは動作はするがインデンテーションが滅茶苦茶でプログラム の構造を正しく反映していない。(そして、おそらく作成者の意図したように は動かない。)プログラムの構造を明確にするために if 文、if 〜 else 文、for 文、while 文は「インデンテーションの約束事」(別紙)の 5.「鉄の掟」に従って、 必ずブレースを使用するように(ただしプログラムの意味(実行結果)が変わらないように)書き換え、さらに 「インデンテーションの約束事」の 0. 〜 4. に従ってインデントしなおせ。
解答は、最初の #include <stdio.h> は省略せよ。
また、解答欄のスペースの都合で、(最後は別として)空行は入れずに記入せよ。
正解例は以下の通りである。
正しくインデントする以前の、ブレースの挿入の段階で間違っているのがほとんどである。 次のような誤りが多い。
あるいは、次の誤りも多い。
これだと、putchar('&'); は i % 3 == 2 のときしか実行されないが、
実際には常に実行される。
上の 2 つの誤答例のようにプログラムの意味(実行結果)を変えてしまうようにブレースを入れてしまう誤答が とても多い。C 言語の文法の大事な部分が抜け落ちて、理解があやふやなまま次へ進めてしまっていると言わざるを得ない。
教科書の p.44, p.46, p.48, pp.74–75, p.82, pp.94–95 に説明があるように、
if や while や for の対象となるのは
1 つの文である。
また pp. 60–61 に説明があるように
単一の文が要求される箇所に、複数の文(や宣言)を置かねばならないときは、 それらをまとめて(ブレースで囲んで)複合文(ブロック)として実現する。
だから、意味を変えないようにブレースを挿入するには、ブレース「{」〜「}」の
間に入るのは1 つの文である。
(スペースや改行の位置は別にして、)ブレースは以下の位置に入る。
(else から始まる文はない、ということにも注意する。)
int main(void) {
int i;
for (i = 1; i <= 6; i++) {
if (i % 2 == 1) {
putchar('#'); }
else {
putchar('$'); }}
if (i % 3 == 2) {
putchar('%'); }
putchar('&');
return 0;
}
開きブレース「{」と閉じブレース「}」の数が合わない、というある意味、
論外の誤答も意外に多くある。
開発チームの他の人や 3 ヵ月後の自分がソースを読んだときに、 このような勘違いが起きないよう、インデンテーションの約束事がある。 特に:
ブレース({ 〜 })の中の文は、外よりも 4
字分(首尾一貫した文字数)を字下げする。
(鉄の掟)if 文, if 〜 else 文 や for 文,
while 文, do 〜 while 文などでは、
選択されたり、繰り返したりされる文が一つだけの場合も、
ブレース({〜})に囲む。
は徹底する必要がある。
なお、このようなブレースを追加しても、 コンパイルされた結果である実行可能ファイルの効率が悪くなる心配はない。
インデンテーションがちゃんとできない人は、 肝心のプログラムの構造がわかっていない、勘でプログラムを作っている、 と判断せざるをえない。教科書を読み返して、C 言語の文法を充分に理解しておくこと。
プログラミング言語の文法は、日本語や英語などの自然言語の文法に比べてはるかに単純である。 理解せずに勘でプログラムを書こうとするのは、時間の浪費で、今後の進歩が望めない。
次のプログラムは一つの値を読み込んで、 それを 1.111 倍した値と、整数として 3 で割った値を表示するプログラムである。 たとえば、100 を入力すると、
整数を入力して下さい: 100↵
入力値を 1.111 倍すると 111.100000
入力値を整数として 3 で割ると 33
と出力する。 空欄を埋めて、プログラムを完成せよ。
正解(例)とコメントは以下のとおりである。 毎週使っているのだから、流石にもう覚えていないといけない。
| 番号 | 正解例 | コメント |
|---|---|---|
| (ⅰ) | %d |
%lf は double 型のための変換指定 |
| (ⅱ) | &n |
& を忘れている解答がときどきある |
| (ⅲ) | %f |
%lf は望ましくない |
| (ⅳ) | 1.111 * n |
(double)(1.111 * n) とか (double)1.111 * n という解答が多いが、
そもそもキャストは必要ない。 |
| (ⅴ) | %d |
%f は double 型のための変換指定 |
| (ⅵ) | n / 3 |
int(n / 3) という書き方は C にはない。int 型へのキャストなら、
(int)(n / 3) だが、そもそもキャストする必要がない。
|
次のプログラムの出力を書け。
正解は、「S T U Y 」である。
「S Y 」という間違いが多いが、
「S T Y 」「S U Y 」という間違いも同じくらい多い。
どういう勘違いをしているのかがわからないが、switch 文は、式の値によって一致する case 〜: に飛んで、
break 文で switch から抜ける、というだけである。
以下の空欄を埋めて、 100 以上 300 以下の 3 の倍数をすべて降順 (つまり、300, 297, 294, …, の順)に出力するプログラムを完成させよ。
正解例は、「k = 300; k >= 100; k -= 3」などである。
変数名が違うの(「i = 300; i >= 100; i -= 3」など)はもちろんダメである。
「k => 100」や「k ≧ 100」という解答があったが、
「=>」や「≧」という演算子は C 言語にはない。
「k <= 100」など、第 2 式の不等号の向きを逆にしてしまう間違いも多い。
これでは一度もループしないか、無限にループし続けるかのどちらかになってしまう。
以下のプログラムは、整数の組のデータを
(i,j) という形式で出力する。
このプログラムの出力を書け。ただし、この問題の解答では、
空白は明示的に空白記号(␣)を、
改行は矢印(↵)を書くこと。
正解は以下の通りである。
(6,6)␣(6,9)␣(6,12)␣↵ (4,4)␣(4,7)␣↵ (2,2)␣↵ (0,0)␣↵
中には、カッコ「(」「)」が出力されていない、
1 行に数字が 1 つしか出力されていない、などの不可思議な誤答があるのだが、もしかして
printf をちゃんと理解していないのではないだろうか?
printf は、%d などの書式指定、\n
などのエスケープ文字以外は、(空白や括弧も含めて)そのまま画面へ出力する。
繰り返しを用いて 1 から 60 までの整数 i に対して、
i を 2 で割った余りと 3 で割った余りを表示するプログラムを作成せよ。
ただし、どちらの余りも 0 のときは、表示せずに飛ばすこと。
1 を 2 で割った余りは 1、3 で割った余りは 1 です。
2 を 2 で割った余りは 0、3 で割った余りは 2 です。
3 を 2 で割った余りは 1、3 で割った余りは 0 です。
4 を 2 で割った余りは 0、3 で割った余りは 1 です。
5 を 2 で割った余りは 1、3 で割った余りは 2 です。
7 を 2 で割った余りは 1、3 で割った余りは 1 です。
8 を 2 で割った余りは 0、3 で割った余りは 2 です。
9 を 2 で割った余りは 1、3 で割った余りは 0 です。
10 を 2 で割った余りは 0、3 で割った余りは 1 です。
11 を 2 で割った余りは 1、3 で割った余りは 2 です。
13 を 2 で割った余りは 1、3 で割った余りは 1 です。
14 を 2 で割った余りは 0、3 で割った余りは 2 です。
15 を 2 で割った余りは 1、3 で割った余りは 0 です。
⋮
(略)
⋮
53 を 2 で割った余りは 1、3 で割った余りは 2 です。
55 を 2 で割った余りは 1、3 で割った余りは 1 です。
56 を 2 で割った余りは 0、3 で割った余りは 2 です。
57 を 2 で割った余りは 1、3 で割った余りは 0 です。
58 を 2 で割った余りは 0、3 で割った余りは 1 です。
59 を 2 で割った余りは 1、3 で割った余りは 2 です。
正解例は以下のとおりである。
あるいは
などである。
「n 回繰り返す」(「for (i = 1; i <= n; i++)」
または、「for (i = 0; i < n; i++) 」)というのは繰返し(for
文)の基本の形である。
これができていないのでは、とても正解に到達することはできない。
while 文や do 文を使っている解答もあったが、for 文を使うべきである。
どちらの余りも 0 のときは、表示せずに飛ばすのであって、 空行を出力するのではない。
printf("… です。", i, i % 2, i % 3);
putchar('\n');
とか
printf("… です。", i, i % 2, i % 3);
printf("\n");
とか、改行の出力だけ別にしている解答が何故か多いのだが、なぜシンプルに
printf("… です。\n", i, i % 2, i % 3);
と書かないのか気になる。
printf(""); という意味のない文を書いている解答がある。他にも
/* 変 */
if (r1 == 0 && r2 == 0) {
} else {
printf("… です。\n", i, r1, r2);
}
のような、中身のない if 文などの変な書き方があった。
下に示すように、正の整数 n を受け取ってディ
スプレイ上に、最初の行に横の長さ(列数)が 1 文字の行を表示、1 行ごとに
1 文字分ずつ長さが長くなっていって、行の文字数が n 文字まで増える左下直角三角形を表示する
プログラムを作成せよ。文字は、
0, @,
1, @, 2, @,
3, @, 4, @,
5, @, 6, @,
7, @, 8, @,
9, @, 0, @,
1, …というように、0 から始まって、
数字と @ が交互に現れ、数字は
9 の次は 0 に戻るようにせよ。
また最後に(空行を開けずに) end と表示せよ。
(n として負の数または 0 を受け取ったときは、end のみを表示する。)
正の整数を入力してください: 5↵
0
@1
@2@
3@4@
5@6@7
end
実行例 2:
正の整数を入力してください: 9↵
0
@1
@2@
3@4@
5@6@7
@8@9@0
@1@2@3@
4@5@6@7@
8@9@0@1@2
end
実行例 3:
正の整数を入力してください: 12↵
0
@1
@2@
3@4@
5@6@7
@8@9@0
@1@2@3@
4@5@6@7@
8@9@0@1@2
@3@4@5@6@7
@8@9@0@1@2@
3@4@5@6@7@8@
end
実行例 4:
正の整数を入力してください: 0↵
end
正解例は以下のとおりである。
あるいは
k % 10 で k の一の位の数字を取り出す手法は、
これまでの例題や演習問題で頻出しているので、流石にもう…
2 や 10(や 20)という定数が現れるのはわかるが、なぜか 11 を使っている誤答が多かった。
ループに入る前に、
のような if 文を入れている解答があるが、不要である。
外側のループは for (i = 0; i < len; i++)、
for (i = 1; i <= len; i++) など
len 回繰り返す形になるはずである。これが for (i = 0; i <= len; i++)
などの len + 1 回繰り返す形だと、最初か最後に余分な空行ができてしまう。