月曜日の試験の採点をしていて,要注意の解答に出会いました.
問題文は以下のとおり.ただし,検証しやすい形式にアレンジしています.
出力に合うよう,______に入る適切なプログラムコードを解答しなさい.
ソース:#include <stdio.h> int main(void) { int i, j; printf("(i,j)="); for (i = 0; i < 3; i++) for (j = ______) printf("(%d,%d),", i, j); printf("\n"); return 0; }出力:
(i,j)=(0,0),(0,1),(0,2),(1,1),(1,2),(2,2),
用意していた解答は,「i; j < 3; j++」です.「j < 3」のところは「j <= 2」でもかまいません.出力を見て,iが0のときは,jは0から2まで,iが1のときは,jは1から2まで,iが2のときは,jは2から2まで,とすれば,jの初期化と(反復継続の)条件が導けますし,増分についてはj++以外,考えなくてもいいでしょう.
さて,びっくりした解答というのは,「j = i; j < 3; j++」です.ケアレスミスと想像できるのですが,当てはめてみますと,
#include <stdio.h> int main(void) { int i, j; printf("(i,j)="); for (i = 0; i < 3; i++) for (j = j = i; j < 3; j++) printf("(%d,%d),", i, j); printf("\n"); return 0; }
となります.「j = j = i」は,iの値をjに代入し,その値をjに代入する,ということで,一つの式で2度,変数jに代入をしています.念のため教科書の一つを開いて確認しましたが,代入の演算では副作用完了点は出てこないので,規格上,してはいけない代入と言えそうです.
しかし
副作用完了点の間では,同一のオブジェクトに対する値の変更は1回のみに限定されます.
(C言語によるプログラミング―スーパーリファレンス編, p.176)
とも書かれています.「j = j」によって値に変更はない,問題はないんだ,という考え方もできます.
と,ここまで思いを巡らせたところで,手元のGCCでコンパイルしてみましょう….
$ gcc -Wall -o jji jji.c jji.c: In function 'main': jji.c:9: warning: operation on 'j' may be undefined
いつものCygwinのほか,Vineでも同様の警告が出ました.なお,実行ファイルはできておりまして,それを実行すると,問題文の出力と一致します.
しかしこの警告は,やっぱりよろしくありませんね.どれだけ減点するか,減点なしにするかは,これから考えます.