for 文道場 (解答編)


目次

  1. 「for 文の意味」編 (04/28 2013 更新) [Update!]
  2. 「for 文にする」編 (04/28 2013 更新) [Update!]
  3. 「for 文の入れ子」編
  4. 「少し厄介な for 文」編
問題編のページへ
「その他」のページへ

「for 文の意味」編


次へ  前へ  問題へ

「for 文の意味: その 1」解答

[2] が正解。間違いやすいのは [6] でしょうか。

[2] 条件、実行文、増分式の順のフローチャート  [6] 実行文、増分式、条件の順のフローチャート 

[2] と [6] の違いは、[2] は条件のチェックを先に行うことです。 だから、その条件が満たされなければ、 実行文は 1 回も実行されない可能性もあります。 (while 文と do while 文の関係に似ています)。
目次へ


次へ  前へ  問題へ

「for 文の意味: その 2」解答

  1. 実行文が 1 つなのにカッコ { } でくくっている:

    これは問題ありません。

  2. 実行文が複数あるのにカッコ { } でくくっていない:

    これは問題があります。 実は、C 言語の文法的にはエラーではないのですが、 意図した動作にはなりません。 問題のコードだと、[実行文 1] のみが for 文の対象となってループになりますが、 [実行文 2]、[実行文 3] は、 その for 文が終わった後に 1 回ずつだけ実行されてしまいます。

  3. 改行を入れていない

    これは問題ありません。 C 言語はフリーフォーマットですから、 改行を入れる、入れないは問題ありません。

    改行が入っていないと for 文自体がどこまで書かれていて、 実行文がどこなのかが見にくいだろうということで、 多くの本では改行を入れて書くことが多いようですが、 書かなくても問題はありません。

    実は私も、むしろ全体を見やすくするために、 短い for 文は改行を入れずに書くことが最近は結構あります。

  4. スペースも入れていない

    これも問題ありません。

    あまり詰まっていると区切りなどが見にくいだろうということで、 多くの本ではスペースを適当に入れて書くことが多いようです。

    また、 「for は関数名ではないので、関数と区別するために for と ( の間にスペースを入れる」という流儀も割と使われています。

    ただ、私は、むしろ全体を見やすくするために、 スペースをあまり入れずに (全然入れないわけではないですが) 書くことが最近は結構あります。

  5. 変なところに改行を入れている

    これも問題ありません。

    特に for 文の条件等が長い場合は、エディタ画面を越える程長い行にする位なら、 適当な位置で改行する方が見やすいかもしれません。

    ただ、[初期値] が長すぎる場合は、 例えば [初期値] の設定は for 文の前に書いてしまうとか、 [増分式] が長すぎる場合は、それを for 文ブロックの一番最後に書くとか、 単独の式として書くことで、長すぎる状態を回避することはできます。

  6. for 文のカッコの中に [初期値]、[条件]、[増分式] を書いてない

    問題ありません。無限ループ用に実際こういう式が使われることがあります。

  7. for 文のカッコの中に何も書いてない

    これはエラーとなります。 for 文のカッコの中には ; で区切られた 3 つの部分が必要なので、 それぞれの部分がなくても、; は必要です。

  8. for 文のカッコを別なカッコにしている

    これはエラーとなります。 丸かっこ ( ) でなければなりません。

(02/25 2011)
目次へ
次へ  前へ  問題へ

「for 文の意味: その 3」解答

for 文を使わずに書くと以下のようになります:

printf("[%d]\n", 1);
printf("[%d]\n", 2);
printf("[%d]\n", 3);
もちろん、次も正解です。
int j;
j = 1;
printf("[%d]\n", j); j = 2;
printf("[%d]\n", j); j = 3;
printf("[%d]\n", j);
厳密に言えば、最も正しいのは以下のような感じでしょうか。
int j;
j = 1;
printf("[%d]\n",j); /* [1] */   j = j+1; /* j == 2 */
printf("[%d]\n",j); /* [2] */   j = j+1; /* j == 3 */
printf("[%d]\n",j); /* [3] */   j = j+1; /* j == 4 */
もちろん /* */ の部分 (C のコメント) は書かなくて結構です。 C 言語では「=」は等号ではなく「右辺の値を左辺に代入する」、 という意味ですので、「j = j+1;」は、 現在の j の値に 1 足した値をあらためて j に代入する、 つまり j の値を 1 増やすということを意味しています。

なお、これだと一番最後の「j = j+1;」は無駄になってますが、 for 文では実際にそれが行われています。

(02/25 2011; 02/28 2011, 04/20 2013 修正)
目次へ
次へ  前へ  問題へ

「for 文の意味: その 4」解答

for 文を使わずに書くと以下のようになります:

printf("[%d]\n", 4);
printf("[%d]\n", 5);
printf("[%d]\n", 6);
for 文が終わった後では longname の値は 7 になっています。 longname に対する式も書けば、これは、 「for 文の意味: その 3」の解答 と同様に、実際には
int longname;
longname = 4;
printf("[%d]\n", longname); longname ++; /* longname == 5 */
printf("[%d]\n", longname); longname ++; /* longname == 6 */
printf("[%d]\n", longname); longname ++; /* longname == 7 */
のようなことが行われています。 C 言語では 「longname ++;」は、「longname = longname+1;」とほぼ同じ意味で、 longname の値を 1 増やしています。 毎回 longname ++ が行われた後で条件の判定が行われていますが、 最後の longname ++ が行われた後の条件の判定で偽 (longname < 7 ではない) となるために for 文は終了しています。 よって、logname の値は 7 になるわけです。

(02/25 2011; 02/28 2011, 04/20 2013 修正)
目次へ
次へ  前へ  問題へ

「for 文の意味: その 5」解答

まず、「k += 2」ですが、これは、「k = k+2」を意味しています。 C では「=」は代入なので、 これで k の値が 2 増やされる (2 足した値があらためて k に代入される) ことになります。 なお、for 文の「k += 2」は、 もちろん「k = k+2」と書いても構いませんし、全く同じ結果になります。

(02/28 2011; 04/20 2013 修正)
目次へ
次へ  前へ  問題へ

「for 文の意味: その 6」解答

まず、[a] と [b] ではループで使われている変数が k と j で違っていますが、 これは本質的な違いではなく、結果には影響しないことに注意しましょう。 「for 文の意味: その 5」の解答 で見たように、[a] は実際には

printf("[%d]\n", 2);
printf("[%d]\n", 4);
printf("[%d]\n", 6);
printf("[%d]\n", 8);
という作業を行っているだけで、 ループ変数が k であるか j であるかに特に意味はありません。 なお、k の式も入れて書けば、
int k;
k = 2;
printf("[%d]\n", k); k = k+2; /* k == 4 */
printf("[%d]\n", k); k = k+2; /* k == 6 */
printf("[%d]\n", k); k = k+2; /* k == 8 */
printf("[%d]\n", k); k = k+2; /* k == 10 */
となります。

[a] と [b] を比較すると、[b] の方は、for 文の [初期値] 部分がありません。 [初期値] 部分は、for 文の中で最も最初に実行される部分ですから、 これを別な場所に移動するとしたら、上を見てわかる通り、 最初の printf() が起こなわれるより前の部分に書かなければいけません。 よって (ア) か (イ) でそれを行うことになりますが、 (イ) に書いてしまうと、それは for 文の最初の [実行文] と見なされて、 毎回実行されてしまうことになります。

しかし、[初期値] 部分は最初の 1 回だけやればいいので、 for 文の実行文である { } よりも前の部分、 すなわち for 文自体の前の部分である (ア) に書くのが正解です。

よって「(ア) に『j=2;』と書く」が正解です。 [b] ではループ変数は j ですから、「k=2;」は間違いです。

ちなみに、(イ) に「j=2;」と書いてしまって

int j;
for ( ; j<=8; j=j+2) {
    j=2;
    printf("[%d]\n", j);
}
とすると、以下のようなことが行われてしまいます。
int j;
j = 2; printf("[%d]\n", j); /* [2] */   j = j+2; /* j == 4 */
j = 2; printf("[%d]\n", j); /* [2] */   j = j+2; /* j == 4 */
j = 2; printf("[%d]\n", j); /* [2] */   j = j+2; /* j == 4 */
j = 2; printf("[%d]\n", j); /* [2] */   j = j+2; /* j == 4 */
...
せっかく [増分式] で j を 2 増やしたのに、 最初の [実行文] である「j = 2;」でまた j に 2 が代入されてしまって値が戻ってしまうことになります。 しかもこの場合、[条件] 部分では毎回「j=4 に対して j<=8 の判定」 が行われてしまうので、この条件は毎回真となり、 よってこの for 文はいつになっても終わらず、 無限ループとなってしまいます (実行したプログラムが止まらなくなる)。

(02/28 2011; 04/20 2013 修正)
目次へ
次へ  前へ  問題へ

「for 文の意味: その 7」解答

for 文も n も使わずに書くと以下のようになります:

printf("[%d]\n", 0); /* n == 0 */
printf("[%d]\n", 1); /* n == 0 */
printf("[%d]\n", 2); /* n == 2 */
printf("[%d]\n", 3); /* n == 2 */
printf("[%d]\n", 4); /* n == 4 */
printf("[%d]\n", 5); /* n == 4 */
なお、これが終わった後では n は 6 になっています。

(03/10 2011; 04/20 2013 修正)
目次へ
次へ  前へ  問題へ

「for 文の意味: その 8」解答

for 文も x も使わずに書くと以下のようになります:

int y;
y = 0;
y = y+1;
y = y+2;
y = y+3;
y = y+4;
printf("[%d]\n", y);
見てわかる通り、 これは 1 から 4 までを加えた結果を表示するものになっています。

printf() の文も (わざと) インデントをつけて書きましたが、 実際には for 文の外にあるので、 最後に 1 回だけしか行われないことに注意してください。

(03/10 2011; 04/20 2013 修正)
目次へ
次へ  前へ  問題へ

「for 文の意味: その 9」解答

for 文も x も使わずに書くと以下のようになります:

int Total = 1;
Total *= 5;
Total *= 4;
Total *= 3;
Total *= 2;
Total *= 1;
printf("[%d]\n", Total);
「Total *= 5;」は「Total = Total * 5;」と同じことを意味します。 よって、これは、
int Total = 1;
Total = 1*5;
Total = 1*5*4;
Total = 1*5*4*3;
Total = 1*5*4*3*2;
Total = 1*5*4*3*2*1;
printf("[%d]\n", Total);
となり、結局1 から 5 までをかけた結果を表示するものになっています。

for 文のループ変数である x の値は最初が 5 で、 実行するたびに x-- (x=x-1 と同じ) によって 1 つずつ小さくなります。 そして「x>0」でなくなった時点、 すなわち「x=0」になったら終わり、ということになります。

(03/10 2011; 04/20 2013 修正)
目次へ
次へ  前へ  問題へ

「for 文の意味: その 10」解答

for 文は使わず、p, q, N を残して書くと以下のようになります:

int p, q, N;
N = 0;
p = 1; /* 初期値 */
q = 5; /* 初期値 */
N += p*q;
p++; /* p == 2 */
q--; /* q == 4 */
N += p*q;
p++; /* p == 3 */
q--; /* q == 3 */
N += p*q;
p++; /* p == 4 */
q--; /* q == 2 */
N += p*q;
p++; /* p == 5 */
q--; /* q == 1 */
N += p*q;
printf("[%d]\n", N);
, (カンマ演算子) で複数の式を並べると、 左から順にそれが実行されますので、 初期値に , で区切って書いた式は、左から順に一つずつ実行されます。 増分式に , で区切って書いた式も、各実行文が終わった後に 左から順に一つずつ実行されます。

つまり、この問題の場合は初期値の設定部分で 2 本の式が実行され、 各実行文が終わった後に 2 本の増分式が実行されるわけです。

(03/10 2011; 04/20 2013 修正)
目次へ
次へ  前へ  問題へ

「for 文の意味: その 11」解答

(ア) に「q=5;」、(ウ) に「q--;」と書いて以下のようにするのが正解です。

int p, q, N;
N = 0;
q = 5;
for (p=1; p<=5; p++) {
    N += p*q;
    q--;
}
printf("[%d]\n", N);
q の初期値の設定である「q=5;」の式は、 最初に 1 度だけ行えばいいので、for 文の前である (ア) に書きます。

一方、増分式の「q--;」は、 元々の for 文では実行文が終わった段階で行われるものですから、 実行文の 2 本目として (ウ) に書くのが正解です。

なお、厳密に言えば、元の式は「q--;」の前に「p++;」が行われますが、 (ウ) に「q--;」と書いた場合は、「q--;」の後に「p++;」が行われる、 という違いがありますが、 この問題の場合には結果に違いはありません。

(03/10 2011)
目次へ
次へ  前へ  問題へ

「for 文の意味: その 12」解答

  1. 「j = 1, 3, 5, 7, 9」が正解。j = 11 になった時点で終了します。

  2. 「j = 3, 4」が正解。j = 5 のときは 2*j は 10 になって 「2*j < 10」を満たしませんので終了します。

  3. 「j = 1, 2, 3, 4」が正解。

    「j % 5」 は「j を 5 で割った余り」を意味しますので、 「j % 5 != 0」は「j を 5 で割った余りが 0 でない」ことを意味し、 よって「j が 5 で割りきれない」ことを意味しますので、 j = 5 のときに条件を満たさなくなります。

  4. 「j = 0, 2, 4, 6, 8」が正解。

    「j += 2」なので、j は 0, 2, 4, ... と偶数をたどります。 j+4 はその 2 つ先の偶数で、「(j+4) % 7 != 0」、 つまり「j+4 が 7 で割りきれない」は j+4 が 14 になったら 満たされなくなります。 よって、j = 10 のときにこの for 文が終了します。

    なお、この条件は少し難しいので、わかりにくければ、 上のように意味を考察するよりも 実際に最初の j を代入して (j+4)%7 の値が何になるかを考えてみるといいかもしれません。

    といった具合です。

  5. 少しインチキに思うかもしれませんが、「実行されない」が正解です。

    これは最初の j = 1 のときから条件 「j < 1」が満たされません。 よって、一度も実行文が実行されずに終了します。 for 文の条件チェックは、 実行文が実行される前に行われることに注意してください。

(03/14 2011)
目次へ
次へ  前へ  問題へ

「for 文の意味: その 13」解答

元の for 文の「for (j=1; j<=10; j++)」は、 j=1,2,3,...,10 (10 個) の j に対して行うもので、 求める for 文の「for (k=0; k<10; k++)」は、 k=0,1,2,...,9 (10 個) の k に対して行うものですから、 繰り返しの数は合っていますが、ひとつずれています。

よって、とりあえず k = j - 1、すなわち j = k + 1 と考えるのが一番楽でしょう。 そうすれば代入文は、

a[(k + 1) - 1] = 2 * (k + 1) + 1;
となるので、これを展開すれば、結局
int k, a[10];
for (k=0; k<10; k++)
  a[k] = 2 * k + 3;
が一つの答えとなります。

(04/28 2013)
目次へ
次へ  前へ  問題へ

「for 文の意味: その 14」解答

元の for 文の「for (j=1; j<=10; j++)」は、 j=1,2,3,...,10 (10 個) の j に対して行うもので、 求める for 文の「for (m=10; m>0; m--)」は、 m=10,9,8,...,1 (10 個) の m に対して行うものですから、 繰り返しの数は合っていますが、反対向きになっています。 これは 2 通りの考え方があるでしょう。

  1. m = 11 - j、すなわち j = 11 - m と考えて対応させる

    この場合は、j = 11 - m をそのまま実行文に代入すれば、

    a[(11 - m) - 1] = 2 * (11 - m) + 1;
    となるので、これを展開すれば、結局
    int m, a[10];
    for (m=10; m>0; m--)
      a[10 - m] = 23 - 2 * m;
    が一つの答えとなります。もちろん、右辺を展開せずに 「2 * (11 - m) + 1;」のままにする解答もあるでしょう。

  2. j = m と対応させる

    m の進み方は j とは逆順なのですが、動く値の集合に違いはありません。 この for 文の実行文では、繰り返しの実行の順番を逆にしても 結果に影響はありませんので、 よって実行文では j = m と見てもいいわけです。 ということで、

    int m, a[10];
    for (m=10; m>0; m--)
      a[m - 1] = 2 * m + 1;
    も一つの解となります。

ただし、後者の考え方は、実行順が結果に影響を及ぼすような for 文、 例えば、

int j, a[11];
a[0] = 1;
for (j=1; j<=10; j++)
   a[j] = 2 * a[j - 1]; /* 一つ前のものの 2 倍を代入 */
のようなものには使えません。 その場合は、前者のように考えるしかありません。

(04/28 2013)
目次へ

「for 文にする」編


次へ  前へ  問題へ

「for 文にする: その 1」解答

解のひとつは以下の通り:

int j;
for (j=1; j<=5; j++)
   printf("3× %d = %d\n", j, 3*j);
{ } で実行文をくくって、
int j;
for (j=1; j<=5; j++) {
     printf("3× %d = %d\n", j, 3*j);
}
としても間違いではありませんし、「5 以下」という条件を「6 未満」にして、
int j;
for (j=1; j<6; j++)
     printf("3× %d = %d\n", j, 3*j);
としてもいいでしょう。無理矢理ですが、j の初期値を 0 にして、
int j;
for (j=0; j<=4; j++)
     printf("3× %d = %d\n", j+1, 3*(j+1));
でも一応間違いではないです。 ただ、最初のが多分一番自然でしょう。

(03/14 2011)
目次へ
次へ  前へ  問題へ

「for 文にする: その 2」解答

解のひとつは以下の通り:

int j;
for (j=1; j<=5; j++)
   printf("5× %d = %d\n", 2*j-1, 5*(2*j-1));
繰り返し文は 5 本で、 1,3,5,7,9 という奇数列は 2*j-1 という式によって作り出すことができます。 ただし、下のように 2*j-1 を一度別な変数に代入する方が見易いかもしれません:
int j, k;
for (j=1; j<=5; j++) {
     k = 2*j - 1;
     printf("5× %d = %d\n", k, 5*k);
}
これらの方法は、カウンタ変数 j の値をひとつずつ増やしているために そこから奇数列を作らないといけなくなっているのですが、 実は以下のようなもう少し自然な解があります:
int k;
for (k=1; k<=9; k+=2)
   printf("5× %d = %d\n", k, 5*k);
1,3,5,7,9 は 2 ずつ値が増えるので、 増分式で 2 つずつ増やせばいいわけです。 数列の言葉で言えば「初期値が 1 で公差 2 の等差数列」となります。

この方法の場合は、終了条件も最後の奇数を指定すればいいだけですが、 終了条件として「5 本」を使いたければ、 j と k を組み合わせた以下のような解もあります:

int j, k;
for (j=1, k=1; j<=5; j++, k+=2)
   printf("5× %d = %d\n", k, 5*k);
初期値の部分と増分式にそれぞれ j と k の設定が入っていますから、 最初は (j, k) = (1, 1)、後は順に (j, k) = (2, 3), (3, 5), (4, 7), ... のように j は 1 ずつ、k は 2 ずつ増えていくことになります。

どれが一番いい、というのは難しいと思いますが、 多分 2 番目か 3 番目のものが自然な解でしょう。

(03/14 2011)
目次へ
次へ  前へ  問題へ

「for 文にする: その 3」解答

このような和は、最初に x = 0 としておいて、 for 文で次々に x に値を追加していけばいいわけです。 例えば以下の通り。

int x, y, j;
double z;
x = 0; y = 0; z = 0.0
for (j=1; j<=100; j++) {
    x += j;
    y += j * j;
}
for (j=1; j<100; j+=2)
  z += 1.0/j;
printf("x = %d, y = %d, z = %f\n", x, y, z);
x, y は同じ 100 項の和なので 1 つの for 文に入れてあります。 「x += j」は「x = x + j」と同じで、j の値を x に追加する文です。 「y += j * j」は、「+=」よりも「*」の方が優先順位が高いので、 「(y += j) * j」ではなく、「y += (j * j)」のように計算されます。

また、「z += 1.0/j」は、分子を 1 にしてしまうと、 j が整数変数のため「1/j」は整数の割り算となり、 その値は j = 1 のとき以外は 0 になってしまいます。 分子を 1.0 にすることで、実数の割り算とみなされ、 正しい分数の値が追加されます。

なお、z の for 文は、

for (j=1; j<50; j++)
  z += 1.0/(2 * j - 1);
でも結構です (が、上の方が多分わかりやすい)。

(04/28 2013)
目次へ
次へ  前へ  問題へ

「for 文にする: その 4」解答

添え字 j に対する一般項を書けば、

a[j] = j + 1, b[j] = 2 * j + 1
なので、これを for 文にすればいいでしょう。
int j, a[50], b[50];
for (j=0; j<50; j++) {
    a[j] = j + 1;
    b[j] = 2 * j + 1;
}

(04/28 2013)
目次へ
次へ  前へ  問題へ

「for 文にする: その 5」解答

添字が偶数しか使いませんが、 この場合例えば以下のような 2 つの考え方があります。

  1. 添字を 2 * j とする

    添字を 2 * j として、j = 1, 2, ..., 50 とする、という手ですが、 この場合一般項は

    a[2 * j] = j
    となるので、結局以下のようにすればいいわけです。
    int j, a[101];
    for (j=1; j<=50; j++)
      a[2 * j] = j;

  2. 添字を j とする

    添字を j として、2 ずつこれを増やして j = 2, 4, 6, ..., 100 とする手ですが、 この場合一般項は

    a[j] = j/2
    となりますから、以下の通りです。
    int j, a[101];
    for (j=2; j<=100; j+=2)
      a[j] = j/2;
    なお、この場合は右辺に代入するものを別な変数にして、
    int j, k, a[101];
    for (j=2, k=1; j<=100; j+=2, k++)
      a[j] = k;
    とする方がわかりやすいかもしれません。

(04/28 2013)
目次へ
次へ  前へ  問題へ

「for 文にする: その 6」解答

この配列を数式で表せば、

a[j] = 100-2*j (j=0,1,...,49)
となりますから、一番簡単な解は以下のものでしょう。
int j, a[50];
for (j=0; j<50; j++)
  a[j] = 100 - 2*j;
かけ算を避ける解として、以下のようなものも考えられます。
int j, k, a[50];
for (j=0, k=100; j<50; j++, k-=2)
  a[j] = k;
for 文のかっこ内には j だけを書くのであれば、以下のようになります。
int j, k, a[50];
k=100;
for (j=0; j<50; j++) {
    a[j] = k;
    k -= 2;
}
前者の k を用いない方法よりも、 多分後者の方が考えやすいだろうと思います。

(04/20 2013)
目次へ
次へ  前へ  問題へ

「for 文にする: その 7」解答

他にも解はあるでしょうが、この配列を数式で表せば、例えば

a[j] = (-1)j = cos(j*π)
などのように表せます。 ただし、累乗も三角関数も実数演算なので誤差も出ますし、 計算も遅い (遅さが気になるのはよほどの場合だけですが) ので、 直接これらを数式にして代入するのは得ではありません。

一番簡単な解は、(-1) をかけ続ける方法でしょうか。

int j, k, a[50];
for (j=0, k=1; j<50; j++, k*=-1)
  a[j] = k;
k を for のかっこから出せば、
int j, k, a[50];
k = 1;
for (j=0; j<50; j++) {
    a[j] = k;
    k *= -1;
}
この問題のように、交互に入れ替わる場合には、 2 での剰余を利用する方法もあります。詳しくは、 「for 文にする: その 8」の解答 を参照してください。

(04/20 2013)
目次へ
次へ  前へ  問題へ

「for 文にする: その 8」解答

この配列を数式で表せば、 「for 文にする: その 7」の解答 の式を利用して、

a[j] = {1-(-1)j}/2 = {1-cos(j*π)}/2
などのように表せるのですが、 「for 文にする: その 7」の解答 と同様、あまりいい式ではありません。

実は C 言語には剰余演算がありますので、もっと簡単に

a[j] = j % 2
と書くことができますから、
int j, a[50];
for (j=0; j<50; j++)
  a[j] = j % 2;
とするのが一番簡単です。

b[j] の方は「一つずれる」と考える、あるいは 1 との反転と考える、 などにより、

b[j] = (j + 1) % 2 = 1 - j % 2
のような式が作れますので、
int j, b[50];
for (j=0; j<50; j++)
  b[j] = (j + 1) % 2;
か、
int j, b[50];
for (j=0; j<50; j++)
  b[j] = 1 - j % 2;
などとなります。

この問題のように、 値が交互に入れ替わる場合には 2 の剰余を利用すると k を用いなくてもできます。例えば、 「for 文にする: その 7」 の問題も、 この a[ ] を 2 倍して 1 から引けばできます:

int j, a[50];
for (j=0; j<50; j++)
  a[j] = 1 - 2 * (j % 2);

(04/20 2013)
目次へ
次へ  前へ  問題へ

「for 文にする: その 9」解答

これには、いくつかの解が考えられます。

  1. 奇数番目と偶数番目で規則が違うので、それを別にやる、 という方法があります。

    int j, k, a[50];
    for (j=0, k=1; j<50; j+=2, k++)
      a[j] = k; /* 偶数番目 */
    for (j=1, k=1; j<50; j+=2, k++)
      a[j] = k; /* 奇数番目 */

  2. これをまとめて、2 つずつやる、という方法もあるでしょう。

    int j, k, a[50];
    for (j=0, k=1; j<50; k++) { /* j は実行部分で増やす */
        a[j] = k;
        j ++;
        a[j] = k;
        j ++;
    }
    なお、「a[j++] = k;」と書けば 「a[j] = k; j ++;」と書いたのと同じことになりますから、これは、
    int j, k, a[50];
    for (j=0, k=1; j<50; k++) {
        a[j ++] = k;
        a[j ++] = k;
    }
    と書くこともできます。

  3. 0.5 ずつ増やして整数部分だけ考える、という手もあります。 ただしその場合、0.5 ずつ増やす値を、 実数変数として保存する必要があります。

    int j, a[50];
    float x;
    for (j=0, x=1.0; j<50; j++, x+=0.5)
      a[j] = x;
    float 変数を int 変数に代入するときに、 小数以下は切り捨てられるので、一応これでうまくいきます。 ただ、実数から整数に切り捨てられたときに、 誤差のせいで一つ前の整数に戻ってしまうかもしれません。 それを避けるために、x の初期値を 1.1 や 1.01 くらいにする、 という手もあります。 なお、明示的に int 値に変換するためにキャスト演算子を使って 「a[j] = (int) x;」と書く方がいいかもしれません。

  4. 「for 文にする: その 8」の解答 のように 2 での剰余を利用する方法もあります。 偶数の j に対しては、a[j] の値から 1 を引くと 0, 1, 2, 3, のように j/2 になりますから、

    a[j] = j/2 + 1
    奇数番目はそれを一つずらして
    a[j] = (j - 1)/2 + 1
    と書けるので、両者をまとめて
    a[j] = (j - (j % 2))/2 + 1
    と書くことができます。よって、
    int j, a[50];
    for (j=0; j<50; j++)
      a[j] = (j - j % 2)/2 + 1;
    が一つの解となります。なお、% と - は % の方が優先順位は上なので、 このように内側のかっこは省略できます。

  5. しかし、ここまでしなくても、 整数の割り算は小数以下の値が無視されます (切り捨てられる) ので、 実はすべての j に対して

    a[j] = j/2 + 1
    で十分です。よって、
    int j, a[50];
    for (j=0; j<50; j++)
      a[j] = j / 2 + 1;
    で実は OK です。

2., 5. の解あたりがシンプルでしょうか。 if 文を使えばもっと他の解も出てくると思います。

(04/20 2013)
目次へ
次へ  前へ  問題へ

「for 文にする: その 10」解答

文字 '0' は、実際には文字「0」を意味する ASCII コード (= 48) の整数値を表しています。 '0' から '9' までは、この '0' (= 48) から順に 48,49,...,57 のように並んでいて、 ヒントとして書いたように「'3' = '0' + 3」のようにして表すことができます。 よって、以下のようになります。

int j;
char a[11];
for (j=0; j<=9; j++)
  a[j] = '0' + j;
a[10] = '\0';
最後の a[10] の設定だけは for ループに入れていませんが、 if 文を使えば以下のようにすれば for ループの中に入れることもできます:
int j;
char a[11];
for (j=0; j<=10; j++) {
    if (j <= 9) a[j] = '0' + j;
    else a[j] = '\0';
}
しかし、これは、for 文の中で無駄な if 文を 10 回繰り返すことになりますから、 前者のように、規則的な部分だけを for 文で行い、 「規則的ではない」一回を for 文の外に出す方がいいでしょう。

(04/26 2013)
目次へ
次へ  前へ  問題へ

「for 文にする: その 11」解答

これは、基本的には「b[j] = a[j + 1]」の繰り返しを行うだけです。 ただし、最後の j == 49 だけはその規則に当てはまらないので、 for 文の外に出せばいいです。

int j;
int a[50], b[50];
/* まずは a[ ] に適当なものを設定 */
for (j=0; j<50; j++)
  a[j] = 2 * j;
/* 次に b[ ] に設定 */
for (j=0; j<49; j++)
  b[j] = a[j + 1];
b[49] = a[0];
if 文を使うか剰余を使えば、 一応最後のものを for ループの中に入れることもできます:

しかし、これらはいずれの場合も for 文の中で最後の一回以外は無駄な if 文、無駄な剰余計算を 繰り返すことになりますから、 前者のように、規則的な部分だけを for 文で行い、 「規則的ではない」一回を for 文の外に出す方がいいでしょう。

(04/26 2013)
目次へ
「その他」のページへ
更新日: 04/28 2013
竹野茂治@新潟工科大学 (shige@iee.niit.ac.jp)