わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

j=j=i

月曜日の試験の採点をしていて,要注意の解答に出会いました.
問題文は以下のとおり.ただし,検証しやすい形式にアレンジしています.

出力に合うよう,______に入る適切なプログラムコードを解答しなさい.
ソース:

#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でも同様の警告が出ました.なお,実行ファイルはできておりまして,それを実行すると,問題文の出力と一致します.
しかしこの警告は,やっぱりよろしくありませんね.どれだけ減点するか,減点なしにするかは,これから考えます.