for と while の使い分け

forとwhileの使い分けの解説ページアイキャッチ

このページでは、forwhile の使い分けについて解説していきます。

C言語のソースコードをベースに解説していきますが、他のプログラミング言語でもループの実現方法に forwhile がある場合は参考になると思います。

また、whiledo while の使い分けについては下記で解説していますので、こちらを知りたい方は下記ページもご参照いただければと思います。

whileとdo whileの違いの解説ページアイキャッチ【C言語】while と do while の違い

forwhile の使い分け

まず前提として、for と while のどちらででも同等のループは実現可能です。

例えば 0 から 9 の数値を表示するのであれば、for ループでは下記のように実現できますし、

forで10回ループ

for (int i = 0; i < 10; i++) {
    printf("%d\n", i);
}

while ループでも下記のように書けば同様のループ処理が実現できます。

whileで10回ループ

int i = 0;
while (i < 10) {
    printf("%d\n", i);
    i++;
}

また、例えばユーザーから値の入力を受け付け、負の値が入力された際にループを終了するような処理であっても、for ループで下記のように書けば実現できますし、

forで負の値入力までループ

int in_val;

scanf("%d", &in_val);

for (; in_val >= 0; ) {
    printf("%d\n", in_val * 2);
    scanf("%d", &in_val);
}

while ループでも下記のように記述すれば実現できます。

whileで負の値入力までループ

int in_val;

scanf("%d", &in_val);

while (in_val >= 0) {
    printf("%d\n", in_val * 2);
    scanf("%d", &in_val);
}

こんな感じで、for ループで実現したループは while ループに書き換えることができますし、その逆も可能です。

さらに、for と while の使い分けの一般的な明確なルールは存在しないと思います。もちろん会社やプロジェクト等で開発を行なっている場合は、そういったルールがあるかもしれませんが、一般的なルールは無いです。

なので、どっちを使っても良いというのが一つの結論です。

ただ、ソースコードを書く上では「読みやすい&バグりにくい」書き方の方が良いですし、これを考慮すれば、下記のように for と while を使い分けをするのが良いと思います。実際に下記で使い分けをしている人も多いのではないかと思います。

  • for:ループの回数がループ開始前に分かっている
  • while:ループの回数がループ開始してみないと分からない

前者に関しては分かりやすいですよね。あらかじめループを 10 回だけ行いたいとか、ユーザーが入力した数値分だけループさせたい場合です。

こういった、必要なループの回数がループを開始する前から分かっている、つまり、ループを開始する前にプログラムとして必要なループ回数が分かる情報を取得可能であるような場合は for ループを使うことが多いと思います。

ただ、どうしてもループ回数がループ開始前には分からない場合があります。

例えば先ほども例に挙げたような、ユーザーからの数値の入力を繰り返し受け付け、負の値が入力された時にループを終了するような処理を実現したい場合です。ユーザーが何を入力するか分からないわけですから、これはもう実際にループを実行してみないとループ回数は分かりません。

こういった、ループ開始前には必要なループ回数が分からない、やってみないと分からない、という場合は while ループを使うことが多いと思います。

for ループの使いどころ

続いては、もう少し具体的な例を見ながら、for ループと while ループそれぞれの使い所やメリットを確認していきたいと思います。

まずは for ループです。

for ループのいいところは、下記のように、どんなループであるかが for () の1行から判断できるところです。

for

for (初期化式; 継続条件式; 変化式) {
    繰り返す処理
}

例えば下記のループであれば、i0 から 1 ずつ増やしながら 繰り返す処理 を繰り返し、i100 になった際に for ループを抜けることが、for (int i = 0; i < 100; i++) の部分を見ればすぐに読み取ることができます。

forループの例1

for (int i = 0; i < 100; i++) {
    繰り返す処理
}

また、for (初期化式; 継続条件式; 変化式) は1セットになっているので、初期化式変化式 の書き忘れも起こりにくいです。

そして、ループに入る前にループ回数が決まっているのであれば、必ず for (初期化式; 継続条件式; 変化式) の形でループを実現することができます。

例えば変数 x の値分だけ回繰り返すような処理であっても、下記のように記述することができますね!

forループの例2

for (int i = 0; i < x; i++) {
    繰り返す処理
}

もちろん、初期化式継続条件式変化式 はループでどんな処理を実現したいかによって記述する内容は変わりますが、いずれにせよループに入る前にループ回数が決まっているのであれば、必ず for (初期化式; 継続条件式; 変化式) の形でループを実現することができます。

そして、この形でループを実現することにより、どのようなループであるかが読み手に伝わりやすくなりますし、さらに 初期化式変化式 の書き忘れのバグを防ぎやすくなります。

それに対して while ループはどうでしょう?

前述の通り、for ループは while ループで書き換え可能であり、while ループを 初期化式継続条件式変化式 を用いて記述すると下記のようになります。

while

初期化式;
while (継続条件式) {
    繰り返す処理

    変化式;
}

もちろん、これでも for ループ同様の処理を実現することは可能なのですが、初期化式継続条件式変化式 が1箇所に集まっていないので、for ループの時に比べると、読み手からするとどういうループであるかが読み取りづらくなります。

また、初期化式while の間に処理があったり、繰り返す処理 が何行にも渡って記述されていると、初期化式継続条件式変化式 が離れてしまって余計に読み取りづらくなります。

何より、上記の書き方だと 初期化式変化式 を書き忘れることがあり、意図した通りにループが動作させられないようなことも結構あります。少なくとも私はこのバグを何回も経験してきました…。もちろんすぐに原因には気付くことは出来るのですが、再度コンパイル&実行して動作確認を行う必要があるため手間がかかり、開発効率も低下します。

こういった理由から、ループを実行する前にループ回数が分かっている場合は、for (初期化式; 継続条件式; 変化式) と1箇所にまとめてループの情報を記述できる for ループの方を使うことの方が多いと思います。

スポンサーリンク

while ループの使いどころ

ただ、ループを開始する時点で必要なループ回数が分からない場合も多々あります。

例えば、何回か例に挙げた、ユーザーからの入力を繰り返し受け付け、負の値が入力されたらループを抜けるような処理を実現しようと思えば、for ループを利用した場合は下記のように記述することになります(入力された値の2倍の値を表示するようにしています)。

forループでの実現

int in_val;

scanf("%d", &in_val);

for (; in_val >= 0; ) {
    printf("%d\n", in_val * 2);
    scanf("%d", &in_val);
}

もちろん、上記でもやりたいことはできるのですが、for (; in_val >= 0; ) の部分がちょっと冗長だと思います。

上記のようにユーザーの入力内容によってループ回数が変わるなど、ループの回数が分からない場合は、とにかくトライしながら 継続条件式 が満たされなくなるまでループを継続することになります。この場合は、逆に回数自体には意味がないことも多く、その場合は回数をカウントするための 初期化式変化式 が不要になります。

そうなると、for ループの for (初期化式; 継続条件式; 変化式) の形式に合わず、for (; in_val >= 0; ) のように 初期化式変化式 部分を空欄にする必要が出てきます。

それに対し、while ループの場合は、下記のように指定が必須なのは 継続条件式 のみになります。while ループの場合は 初期化式変化式 が必須ではないので、継続条件式 のみが重要である場合に、for ループよりも簡潔に処理を記述することができます。

while

while (継続条件式) {
    繰り返す処理
}

例えば先ほどの for ループの例を while ループで書き換えれば下記のように変化することになります。

whileループでの実現

int in_val;

scanf("%d", &in_val);

while (in_val >= 0) {
    printf("%d\n", in_val * 2);
    scanf("%d", &in_val);
}

for (; in_val >= 0; ) に比べれば、while (in_val >= 0) の方が簡潔で読みやすいと感じる人も多いと思います。

他の例としては、ファイルからの文字の取得に関しても while を使うことが多いです。例えば fgetc 関数ではファイルから1つずつ文字を取得することができます。

なので、ファイル内の文字数分 fgetc 関数を繰り返し実行すれば、ファイル内の全ての文字を取得することができます。

ただし、ファイルによって文字数は異なるため、ファイル内の全ての文字を取得するために必要な fgetc 関数の繰り返し回数がループを開始する前には分かりません。この場合も、実際に fgetc 関数を実行してファイルの最後の行まで読み込んだかどうかを確認しながらループを行う必要があります(すでにファイルの最後まで読み込み済みであるかどうかは、fgetc 関数が EOF を返却したかどうかで判断できる)。

この、ファイルから文字を全て取得する処理の一例は下記のようになります。

ファイルからの文字取得

FILE *stream = fopen(FILE_NAME, "r");
if (stream == NULL) {
    printf("fopen error\n");
    return 0;
}

int c;
while ((c = fgetc(stream)) != EOF) {
    printf("%c", c);
}

fclose(stream);

こんな感じで、ループを開始する前に必要なループ回数が分からない場合、つまり実際にループを回して試してみないと必要なループ回数分からない場合は while を使うことが多いです。これは、この場合は 継続条件式 のみが必要なことが多く、継続条件式 のみが必要なのであれば while の方が簡潔に記述できるからです。

まとめ

このページでは、forwhile の使い分けについて解説しました!

forwhile の使い分けについては一般的な明確なルールはありませんが、下記で使い分けることが多いです。

  • for:ループの回数がループ開始前に分かっている
  • while:ループの回数がループ開始してみないと分からない

前者の場合は for (初期化式; 継続条件式; 変化式) の形式でループを実現することができ、1箇所にループに関する情報が集まるので読みやすく、さらに記述漏れによるバグも減らせます。

後者の場合は、必要なのが 継続条件式 だけになることが多く、while (継続条件式) だけでループが実現できる while の方が簡潔な記述になります。

まぁただ、これだけが全てではないですけどね…。例えば文字列の長さが分からないような場合でも、文字列の最後にヌル文字('\0')があることを考慮して文字列の全文字に対する繰り返し処理を下記のように for ループで書くこともありますし。

全文字に対する処理

void printStr(char *str) {
    for (int i = 0; str[i] != '\0'; i++) {
        printf("%c", str[i]);
    }
    printf("\n");
}

そういう意味では、for (初期化式; 継続条件式; 変化式) の形式で書ける場合は for を使った方が良いと言った方が良いかもしれません。

いずれにせよ、重要なのは「読みやすくバグりにくい」ソースコードを書くことだと思います。

ループの継続条件が複数存在するような場合なども、そのまま上記の考え方が当てはまらない場合があると思いますが、その時は「読みやすくバグりにくい」ソースコードにするにはどうすれば良いかを考えながら、forwhile を使い分けるようにしましょう!

また、ページの最初でも紹介したように、C言語にはループの実現方法として do while も用意されています。

whiledo while の使い分けについては下記で解説していますので、こちらも是非読んでみてください!

whileとdo whileの違いの解説ページアイキャッチ【C言語】while と do while の違い

オススメの参考書

C言語学習中だけど分からないことが多くて挫折しそう...という方には、下記の「スッキリわかるC言語入門」がオススメです!

まず学習を進める上で、参考書は2冊持っておくことをオススメします。この理由は下記の2つです。

  • 参考書によって、解説の仕方は異なる
  • 読み手によって、理解しやすい解説の仕方は異なる

ある人の説明聞いても理解できなかったけど、他の人からちょっと違った観点での説明を聞いて「あー、そういうことね!」って簡単に理解できた経験をお持ちの方も多いのではないでしょうか?

それと同じで、1冊の参考書を読んで理解できない事も、他の参考書とは異なる内容の解説を読むことで理解できる可能性があります。

なので、参考書は2冊持っておいた方が学習時に挫折しにくいというのが私の考えです。

特に上記の「スッキリわかるC言語入門」は、他の参考書とは違った切り口での解説が豊富で、他の参考書で理解できなかった内容に対して違った観点での解説を読むことができ、オススメです。題名の通り「なぜそうなるのか?」がスッキリ理解できるような解説内容にもなっており、C言語入門書としてもかなり分かりやすい参考書だと思います。

もちろんネット等でも色んな観点からの解説を読むことが出来ますので、分からない点は別の人・別の参考書の解説を読んで解決していきましょう!もちろん私のサイトも参考にしていただけると嬉しいです!

入門用のオススメ参考書は下記ページでも紹介していますので、こちらも是非参考にしていただければと思います。

https://daeudaeu.com/c_reference_book/

同じカテゴリのページ一覧を表示