わさっきhb

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

nlmate'

いきなりですが問題です.出力と一致するよう,プログラムコードの「………」を正しいCのコードに置き換えてください.

プログラムコード(各問共通):

  for (i = 0; i < 3; i++)
    for (j = ………)
      printf("(%d,%d)", i, j);

出力1:

(0,0)(0,1)(0,2)(1,0)(1,1)(1,2)(2,0)(2,1)(2,2)

出力2:

(0,2)(1,1)(1,2)(2,0)(2,1)(2,2)

出力3:

(0,0)(2,2)(0,2)(2,0)(1,1)

出力1と出力2については,nlmateにちょうどそのものの出題があるので,答えは書かないことにします.出力2は昨年度の担当科目の試験問題で出し,今年度はプレ試験問題で出して解説しました.
出力1から出力3まで,変数i, jの変化を図にすると,次のようになります.
出力1:

出力2:

出力3:

それで出力3ですが,iも増えたり減ったり,jも増えたり減ったりで,2重ループとして素直に記述できそうにありません.
こういうときは状態遷移です.変数iとjの値のペア(i,j)を一つの状態とし,一つの式で2つの変数に代入して,両方の値を変えてやります.すなわち,

  • (i,j)=(0,0)なら,(i,j)←(2,2)
  • (i,j)=(2,2)なら,(i,j)←(0,2)
  • (i,j)=(0,2)なら,(i,j)←(2,0)
  • (i,j)=(2,0)なら,(i,j)←(1,1)
  • (i,j)=(1,1)のときも考えておきましょう…(i,j)←(3,3) *1

一つの式で2つの変数に代入というのは,コンマ演算子でできます.forの増分の中で,else ifは使えませんが,3項演算子入れ子で表現します.プログラムは以下のようになります.

#include <stdio.h>

int main(void)
{
  int i, j;

  for (i = 0; i < 3; i++)
    for (j = 0; j < 3; (i == 0 && j == 0) ? (i = 2, j = 2) :
                       (i == 2 && j == 2) ? (i = 0, j = 2) :
                       (i == 0 && j == 2) ? (i = 2, j = 0) :
                       (i == 2 && j == 0) ? (i = 1, j = 1) :
                                            (i = 3, j = 3))
      printf("(%d,%d)", i, j);
  printf("\n");

  return 0;
}

3項演算子のインデント方法については,かつてはてブしていた三項演算子?:の正しい書き方を見直しました.
こうしてみると,外側の,iに関するfor文は1回しか実行しないので,ループにする必要性がないことに気づきます.実のところ,nlmateに入れるにはよろしくない問題です.それと,「(i == 0 && j == 0)」などのカッコは除去できるのに対し,「(i = 2, j = 2)」ほかのほうは除去できません.演算子の優先順位を再確認する,またとない機会になりました.

*1:対称性からこうしましたが,出力1,出力2と同じ「終わらせ方」にするなら,(i,j)←(2,3)と書くべきでしょうね.