情報基礎演習II − 第8回


1.制御構造(つづき)


for

次のような一定回数の繰り返しは、プログラムの至る所で現れます。
int i;
i = 0;
while (i < 5) {
    printf("おはようさん\n");
    i++;
}
for というキーワードを使えば、これを次のように簡略化できます。
for (i = 0; i < 5; i++) {
    printf("おはようさん\n");
}
これも for ( ) に続く { } 内が単一の文のときは、{ } を省略できます。
for (i = 0; i < 5; i++)
    printf("おはようさん\n");
for の ( ) 内は ; に区切られた3つの部分からなり、 それぞれ「前処理」「継続条件」「継続処理」を記述します。 これらは右のような順序で実行されます。
for (前処理; 継続条件; 継続処理) {
    繰り返すプログラム;
    ...
}
上の例では、i は 0→1→2→3→4 と変化し、 i == 5 となったときに条件を満たさなくなり、 繰り返しを終了します。

■課題31■

for の用途は while 同様、 一定回数の繰り返しだけに限りません。 次の例は、文字列の1字1字を取り出します。

for (i = 0; str[i] != '\0'; i++) {
    printf("%d 文字目は %c\n", i, str[i]);
}
これは文字型の配列変数 str に格納されている文字列を、 先頭から1字ずつ取り出して出力します。 文字列の最後は '\0' で終わっていますから、 これが現れたら繰り返しを終了します。

for の継続条件を省略すると、処理を無限に繰り返します。

for (i = 0; ; i++) { ... }
i を1ずつ増しながら { ... } 内の処理を無限に繰り返します。
for ( ; ; ) { ... }
{ ... } 内の処理を無限に繰り返します。

while は ( ) 内の条件を省略できません。 上と同じことを行う場合には、条件として非 0 の整数値を指定します。

while (1) { ... }
条件において非 0 の整数は真を表し、0 は偽を表します。

while と同様、break や continue によって繰り返しを中断/継続できます。

for ( ; ; ) {
    scanf("%d", &x);
    if (x == 0) break; /* 0 が入力されたら終わり */
    sum += x;
}
この例は入力された数値を合計します。 改行だけが入力されると繰り返しを終わります。

■課題32■


do 〜 while

これらの他に処理を繰り返す手段として、 do 〜 while があります。 これは do と while の間に繰り返すべきプログラムを書きます。
int i;
i = 10;
do {
    printf("Hello\n");
}
while (--i > 0);
while () { ... } とは異なり、 繰り返しの継続条件の判定を { ... } の実行後に行うため、 継続条件によらず最低一回は処理を実行します。

上の例では、最初 i = 1 でも i = 0 でも1回 Hello が表示されます。

■課題33■


break と continue

while のような繰り返しを、 while に続く ( ) 内の条件以外の要因で終了させたり、 途中をはしょったりするために、 break と continue というキーワードが用意されています。
int i;
i = 0;
while (i < 5) {
    if (i == 3) break;
    printf("%d 回目\n", ++i);
}
これは i == 3 になったところで break が実行されて while による繰り返しが終わるので「2 回目」までしか出力されません。
int i;
i = 0;
while (i < 5) {
    if (i == 3) continue;
    printf("%d 回目\n", ++i);
}
これは i == 3 になったところで continue が実行されて 残りの部分(printf)が飛ばされるので「3 回目」は出力されません。

■課題34■


switch

キーボードから入力された数値に従って、 異なる処理をするようなプログラムを考えます。
int x;

scanf("%d", &x);

if (x == 1) {
    printf("1番の処理\n");
}
else if (x == 2) {
    printf("2番の処理\n");
}
else if (x == 3) {
    printf("3番の処理\n");
}
else if (x == 4) {
    printf("4番の処理\n");
}
else {
    printf("そのような処理はできません\n");
}
この例のように、ある整数値に対して、 実行する処理が決まっているときは、switch を使うと便利です。
int x;

scanf("%d", &x);

switch (x) {
case 1: /* x == 1 のときここから下を実行 */
    printf("1番の処理\n");
   break;
case 2: /* x == 2 のときここから下を実行 */
    printf("2番の処理\n");
    break;
case 3: /* x == 3 のときここから下を実行 */
    printf("3番の処理\n");
    break;
case 4: /* x == 4 のときここから下を実行 */
    printf("4番の処理\n");
    break;
default: /* 上のいずれにも該当しないときここから下を実行 */
    printf("そのような処理はできません\n");
    break;
}
switch は、 このとき、 また、switch において break は、 switch ( ) { ... } からの脱出を意味します。
switch (x) {
case 1:
    printf("1番の処理\n");
case 2:
    printf("2番の処理\n");
    break;
...
上の例のように case 2: の前の break が無い場合は、 x == 1 のときは case 1: の処理の後 case 2: の処理も実行されます。

■課題35■


goto

次の1つ目のプログラムの break は switch の処理からの脱出になるため、 2つ目のプログラムのように for による繰り返しを終了することはできません。
for (i = 0; i < 100; i++) {
    switch (data[i]) {
    case 0:
        printf("%d番目のデータが0になっています\n");
        break; /* この break は switch から抜け出すだけ */
    }
}

for (i = 0; i < 100; i++) { if (data[i] == 0) { printf("%d番目のデータが0になっています\n"); break; /* この break は for による繰り返しを終了する */ } }
上の1つ目の例のように switch を使った場合に、 2つ目の例のように for の外側まで脱出したいときには、 goto を使うことができます。
    for (i = 0; i < 100; i++) {
        switch (data[i]) {
        case 0:
            printf("%d番目のデータが0になっています\n");
            goto out_of_loop; /* out_of_loop というラベルに直行 */
        }
    }
out_of_loop:
    printf("終了\n");
「goto ラベル;」とすると、 そこから(同じ関数内にある)「ラベル:」が書かれたところに処理を移します。 「ラベル:」の後ろには文が必要です。 実行する処理がなければ、空文(セミコロン ";" のみ)を置いてください。

for や while による繰り返しが2重になっている場合も同様です。

    for (i = 0; i < 100; i++) {
        for (j = 0; j < 100; j++) {
            if (data[i][j] == 0) goto exit_loop;
        }
    }
exit_loop:
    printf("(%d,%d) のデータが0です\n", i, j);
goto は安易に使うべきではありません。 エラー処理など、goto を使わないことによって、 かえってソースプログラムの可読性(読みやすさ)を下げることが 明らかな場合だけに限定して使用した方が無難でしょう。

■課題36■