中間テストはペーパーテストが 12 点満点、
オンラインテストが 8 点満点で採点する。
(ただし、最終的な成績の計算にはこの半分 — ペーパーテスト 6点満点、
オンラインテスト 4 点満点 — の割合で用いる。)
期末テストは、もっと難易度は高くなる。
今回はテストであるので、NG というメッセージがあっても、 再提出する必要はない。
ペーパーとオンラインを合算して、得点率が 6 割未満の者には、 追試験を実施する予定である。詳細は追って連絡する。(nov24_1.c へのメッセージにペーパーテスト・オンラインテストの得点を通知する予定である。
以下のプログラムは動作はするがインデンテーションが滅茶苦茶で、 プログラムの構造を正しく反映していない。プログラムの構造を明確にするために 「プログラミング」のインデンテーションの約束事(別紙)に厳密に従って (特に Ⅴ 番目のルールに注意)、必要に応じてブレースを挿入し、 インデントしなおせ。ブレース内の字下げは 4文字分とせよ。
もちろん、プログラムの意味(実行結果)が変わらないようにすること。
解答は、最初の #include <stdio.h> は省略せよ。また、 解答欄のスペースの都合で、空行は入れずに記入せよ。
int main(void) { int i, j; for (i = 0; i < 12; i++) for (j = 0; j < 12; j++) if (j % 3 == 0) putchar('@'); if (i % 5 == 0) putchar('*'); else putchar('#'); putchar('\n'); return 0; }
正解は以下の通りである。
int main(void) { int i, j; for (i = 0; i < 12; i++) { for (j = 0; j < 12; j++) { if (j % 3 == 0) { putchar('@'); } } } if (i % 5 == 0) { putchar('*'); } else { putchar('#'); } putchar('\n'); return 0; }
正解したのは 19 名で、22.1 % (19/86) だった。 問1 の正解/不正解と平均点の関係は以下の通りである。
問1 | ペーパー(問1以外) | オンライン |
---|---|---|
正解 | 9.74 | 7.68 |
不正解 | 7.46 | 2.58 |
オンライン試験の得点にくっきりと差が出ている。 特に、オンラインが無得点で問 1 を正解した人は皆無だった、 問 1 を正解した人は、オンラインテストで、一人が 4 点だったのを除いて 7 点以上得点していた。(ちなみに、オンライン 7 点以上は 34名)
インデンテーションがちゃんとできない人は、肝心のプログラムの構造がわかっていない、 勘でプログラムを作っている、 と判断せざるをえない。教科書を読み返して、C 言語の文法を充分に理解しておくこと。
プログラミング言語の文法は、日本語や英語などの自然言語の文法に比べてはるかに単純である。 理解せずに勘でプログラムを書こうとするのは、時間の浪費で、今後の進歩が望めない。
プログラムの意味(実行結果)を変えてしまうようにブレースを入れてしまう誤答が、 とても多い。if や for の対象となるのは、1 つの文だから、 (スペースや改行の位置は別にして、)ブレースは以下の位置に入る。
int main(void) { int i, j; for (i = 0; i < 12; i++) { for (j = 0; j < 12; j++) { if (j % 3 == 0) { putchar('@');}}} if (i % 5 == 0) { putchar('*'); } else { putchar('#'); } putchar('\n'); return 0; }
教科書の p.43, p.44, p.46, pp.58-59, p.73, p.80, pp.90-91 を確認しておくこと。
例えば、以下のようにブレースをいれてしまうと、プログラムの意味が変わってしまう。
/* 間違い */
int main(void) {
int i, j;
for (i = 0; i < 12; i++) {
for (j = 0; j < 12; j++) {
if (j % 3 == 0) putchar('@');
if (i % 5 == 0) {
putchar('*');
} else {
putchar('#');
putchar('\n');
}
}
}
return 0;
}
開発チームの他の人や 3 ヵ月後の自分がソースを読んだときに、 このような勘違いが起きないよう、インデンテーションの約束事がある。 特に:
ブレース({ 〜 })の中は、外よりも 4 字分(首尾一貫した文字数)を字下げする。
if 文, if 〜 else 文 や for 文, while 文, do 〜 while 文などでは、 選択されたり、繰り返したりされる文が一つだけの場合も、 ブレース({〜})に囲む。
は徹底する必要がある。
なお、このようなブレースを追加しても、 コンパイルされた結果である実行可能ファイルの効率が悪くなる心配はない。
次のプログラムは一つの整数値を読み込んで、 それを11倍してから(整数として)10で割った値と、0.5 倍した値を表示するプログラムである。
たとえば、25 を入力すると、
それを 11 倍してから 10 で割った値は 27 です。 それを 0.5 倍した値は 12.500000 です。
と出力する。 空欄を埋めて、プログラムを完成せよ。
int main(void) { int num; printf("整数を入力して下さい: "); scanf("", ); printf("それを 11 倍してから 10 で割った値は です。\n", ); printf("それを 0.5 倍した値は です。\n", ); return 0; }
正解(例)とコメントは以下のとおりである。
番号 | 正解例 | コメント |
---|---|---|
(ⅰ) | %d | |
(ⅱ) | &num | & の付け忘れがやや目立った。 |
(ⅲ) | %d | |
(ⅳ) | num * 11 / 10 | |
(ⅴ) | %f | %lf は不可 |
(ⅵ) | 0.5 * x | 「x / 2.0」や「(double)x / 2」なども可 「(double)x * 0.5」や「(double)(x * 0.5)」 の (double) は不要 |
次のプログラムの出力を書け。
int main(void) { int k = 42; if (k % 4 == 0) { printf("A "); } else if (k % 2 == 0) { printf("B "); } if (k % 3 == 0) { printf("C "); } else if (k % 7 == 0) { printf("D "); } printf("\n"); return 0; }
正解は、「B C 」。
k % 4 == 0 という条件は成り立たないので、else 部の if (k % 2 == 0) { … } が評価され、k % 2 == 0 が成り立つので、B と出力される。 if (k % 3 == 0) { … } は、else 部ではなく、 次の文なので評価される。 k % 3 == 0 という条件が成り立つので C と出力される。 else 部の if (k % 7 == 0) { … } は評価されない。
問3 | ペーパー(問3以外) | オンライン |
---|---|---|
正解 | 7.16 | 3.93 |
不正解 | 4.54 | 2.51 |
0 以上 120 以下の 3 の倍数をすべて降順 (つまり、120, 117, 114, …, 3, 0の順)に出力するプログラムを完成させよ。
int main(void) {
int k;
for ( ) {
printf("%d ", k);
}
printf("\n");
return 0;
}
正解例は、「k = 120; k >= 0; k -= 3」。
k -= 3 のところは、k = k - 3 でもよい。 ここを、単に k - 3 とする間違いが多い。 (第 1 式と)第 3 式は式の値は無視されるので、通常は代入である。
「k ≧ 0」などという解答があったが、 そんな文字はキーボードにない。
「k => 0」、「k - 3 = k」 などの間違いもあった。単純に勉強不足か、方向が間違っていると思われる。
int main(void) { int i, j, n = 4; for (i = 1; i < n; i++) { for (j = i; j >= 1; j--) { printf("(%d,%d) ", i + j, i - j); } printf("\n"); } return 0; }
正解は以下の通りである。
(2,0)␣↓ (4,0)␣(3,1)␣↓ (6,0)␣(5,1)␣(4,2)␣↓
最後にもう一行、(8,0)␣(7,1)␣(6,2)␣(5,3)␣↓ を付け足してしまう誤りが多かった。 for (i = 1; i < n; i++) という形は n - 1 回しか繰り返さないことに注意する。
正の整数を入力してください: 4↵
2 6 18 54
実行例 2:
正の整数を入力してください: 6↵
2 6 18 54 162 486
実行例 3:
正の整数を入力してください: -1↵
実行例 4:
正の整数を入力してください: 1↵
2
正解例は以下のとおりである。
#include <stdio.h> int main(void) { int i, num, k = 2; printf("正の整数を入力してください: "); scanf("%d", &num); for (i = 0; i < num; i++) { printf("%d ", k); k *= 3; } putchar('\n'); return 0; }
平均点は 1.793点
「num 回繰り返す」(for (i = 0; i < num; i++) または、 for (i = 1; i <= num; i++) )というのは繰返しの基本の形だが、 それができていない解答が多い。
for 文は、繰返しを制御する変数の値を変える操作は、for のあとの括弧の中に書く。次のような書きかたは、動作は変らなくても見にくく、 for 文を使う意味がなくなってしまう。
/* 悪い例 */ i = 0; for (k = 2; i < num; k *= 3) { printf("%d ", k); i++: }
printf("%d ", k *= 3) のように、k *= 3 を printf のなかに書くことにこだわって、 結果としてできていないことが多い。
2 * 3 ^ i のように書いている解答があったが、 「^」は C 言語では累乗の演算子ではない。 (「^」を累乗に使うのは FORTRAN や BASIC 系の言語である。)
毎週の演習問題では、完成し(たと思っ)てから提出するので、 今回は普段は見られない間違いが多かったが、 k = 3 k などはあまりに初歩的な間違いである。
やはりインデンテーションが約束事にそってできていない解答が多い。 この問題の場合はインデンテーションの誤りは 10 〜 20 % の減点とする。
下に示すように、正の整数 n を受け取ってディスプレイ上に、 1 文字めが 1、 2 文字めが 3、3 文字めが 5、 4 文字めが 7、5 文字めが 9、 6 文字めが 1、 7 文字めが 3、8 文字めが 5、 9 文字めが 7、10 文字めが 9、 11 文字めが 1、… というように1357913579…を繰り返し、 一辺の長さが n の正方形を表示するプログラムを作成せよ。(負の数または 0 を受け取ったときは、何も表示しなくてよい。)
実行例 1:正の整数を入力してください: 4↵
1357
9135
7913
5791
実行例 2:
正の整数を入力してください: 11↵
13579135791
35791357913
57913579135
79135791357
91357913579
13579135791
35791357913
57913579135
79135791357
91357913579
13579135791
実行例 2:
正の整数を入力してください: 0↵
正解例は以下のとおりである。
#include <stdio.h> int main(void) { int i, j, num, k = 1; printf("正の整数を入力してください: "); scanf("%d", &num); for (i = 0; i < num; i++) { for (j = 0; j < num; j++) { printf("%d", k % 10); k += 2; } putchar('\n'); } }
平均点は 1.789 点で問 1 とほとんど変らなかった。