ログイン
kid's world

一度は必ず実行

一度は必ず実行するdo while文

そうはいっても,一度も実行されないで通過されては困る,という場合もあるだろう。条件にかかわらず,必ず文を一度は実行したい場合は,do while文という制御文を使うとよい(Fig. 3)。

Fig. 3: do while文の構文

do
  文
while (式);

do while文では,最初に文が実行され,そのあとに式が評価される。List 6は,それを確認するプログラム例だ。これは,以前の羊を数えるプログラムであるList 5のwhile文を,do while文に書き換えたものである。実際に実行してみれば,条件に合わなくても必ず一度は実行されることがわかるだろう。

List 6: 必ず一度は実行される

#include <stdio.h>

main()
{
  int i=100;
  
  do {
    i++;
    printf("羊が%d匹、",i);
  } while (i<100);
  printf("…ぐーぐー。\n");
}

do whileを使うとよい場合

while文は条件が成り立つ「間」,文を繰り返し実行する制御文とすれば,do while文は条件が成り立つ「まで」,文を繰り返し実行する制御文と考えることができる。たとえば,ユーザに1〜12までの数値を入力してほしいが,それ以外の数値は入力してほしくないとしよう。望んでいない数値が入力されたら,もう一度入力を繰り返すようにすればよいわけだが,これを実現するにはwhile文を使えばよいか,それともdo while文を使えばよいのだろうか。

答えはdo while文である。1〜12の数値になる「まで」,入力を繰り返せばよいからだ。とはいっても実際に式に書く条件は「1〜12ではない」となるのではなく,「1未満か12を超える」となるので注意しよう。具体的な例をList 7に示す。

List 7: do while文で再入力を行う

#include <stdio.h>

main()
{
  int y=0;
  
  do {
    printf("1から12までの整数を入力してください。\n");
    scanf("%d", &y);
  } while (y<1 || 12<y);

  printf("あなたが入力した数値は、%dです。\n", y);
}

scan関数の注意点

さて,先ほどのプログラムを使えば必ずyには1〜12までの数値が入るようになったが,実はまだ問題がある。これはdo while文の問題点ではなく,scanf関数の問題である。少し横道にそれるが,ここで説明をしておこう。

その問題は,数値以外のもの(たとえば文字)を入力した場合に発生する。

Fig. 4はユーザが「a」という文字を入力した実行例だが,そのあと再度の入力を促すメッセージは表示されても,無限に出てきて止まらなくなってしまう。これはなぜかというと,scanf関数は指定された「%d」という変換文字によって文字を数値に変換しようと思ったのだが,実際に入力されたのは「a」という文字であったため変換できず,その変換をしないで処理を終えるからだ。そしてこの文字は何も処理されないまま入力バッファに蓄えられる。変数yの値は変更されていないので0のままであり,これはdo while文の条件に合致し,繰り返しが起こる。そして,またscanf関数が実行され,入力バッファを見てみるとやはり「a」が入っていて……と無限に繰り返すわけである。

Fig. 4: List 7の実行例

1から12までの整数を入力してください。
a
1から12までの整数を入力してください。
1から12までの整数を入力してください。
1から12までの整数を入力してください。
1から12までの整数を入力してください。
1から12までの整数を入力してください。
1から12までの整数を入力してください。
1から12までの整数を入力してください。
1から12までの整数を入力してください。
1から12までの整数を入力してください。
1から12までの整数を入力してください。
1から12までの整数を入力してください。
…

どうすればこの無限ループから抜け出せるのだろうか。scanf関数はこのような場合に有用な値を返している。それは,変換できた項目の数である。List 7のプログラムのscanf関数は,正しく変換されたときに1という数値を返しているのだ。これをうまく使えばよい。つまり,戻り値が1ではなかったときに,その無効な文字をバッファから取り除いてしまえばいいのだ。

1項目ぶん(空白文字で区切られた部分)を取り除くには,文字列を読み取る変換文字「%s」を使って文字列として読み込んで,破棄してしまえばいい。したがって,適当なchar型配列sを作って,

scanf("%s",s);

とすればよい。しかし実際にはchar型配列を作らなくても,変数に格納せずにそのまま破棄したい場合は「%*s」というように,変換文字の前に「*」をつければよい。つまり,

scanf("%*s");

と書くだけでよいのだ。では,List 7の改良版をList 8に示そう。

List 8: List 7の改良版

#include <stdio.h>

main()
{
  int y=0;
  
  do {
    printf("1から12までの整数を入力してください。\n");
    if (scanf("%d", &y)!=1)
      scanf("%*s");
  } while (y<1 || 12<y);

  printf("あなたが入力した数値は、%dです。\n", y);
}

これで,どんな文字が入力されても,無限ループに陥らずに,ほしい数値だけをとることができるようになった。


決まった回数繰り返す」へ進む

広告


©Toshio Koide 1996-2007.

目次

リンクについて

リンクは御自由にどうぞ。

メール

mail.gif

広告