このページでは、for
と while
の使い分けについて解説していきます。
C言語のソースコードをベースに解説していきますが、他のプログラミング言語でもループの実現方法に for
と while
がある場合は参考になると思います。
また、while
と do while
の使い分けについては下記で解説していますので、こちらを知りたい方は下記ページもご参照いただければと思います。
for
と while
の使い分け
まず前提として、for
と while
のどちらででも同等のループは実現可能です。
例えば 0
から 9
の数値を表示するのであれば、for
ループでは下記のように実現できますし、
for (int i = 0; i < 10; i++) {
printf("%d\n", i);
}
while
ループでも下記のように書けば同様のループ処理が実現できます。
int i = 0;
while (i < 10) {
printf("%d\n", i);
i++;
}
また、例えばユーザーから値の入力を受け付け、負の値が入力された際にループを終了するような処理であっても、for
ループで下記のように書けば実現できますし、
int in_val;
scanf("%d", &in_val);
for (; in_val >= 0; ) {
printf("%d\n", in_val * 2);
scanf("%d", &in_val);
}
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 (初期化式; 継続条件式; 変化式) {
繰り返す処理
}
例えば下記のループであれば、i
を 0
から 1
ずつ増やしながら 繰り返す処理
を繰り返し、i
が 100
になった際に for
ループを抜けることが、for (int i = 0; i < 100; i++)
の部分を見ればすぐに読み取ることができます。
for (int i = 0; i < 100; i++) {
繰り返す処理
}
また、for (初期化式; 継続条件式; 変化式)
は1セットになっているので、初期化式
や 変化式
の書き忘れも起こりにくいです。
そして、ループに入る前にループ回数が決まっているのであれば、必ず for (初期化式; 継続条件式; 変化式)
の形でループを実現することができます。
例えば変数 x
の値分だけ回繰り返すような処理であっても、下記のように記述することができますね!
for (int i = 0; i < x; i++) {
繰り返す処理
}
もちろん、初期化式
や 継続条件式
、変化式
はループでどんな処理を実現したいかによって記述する内容は変わりますが、いずれにせよループに入る前にループ回数が決まっているのであれば、必ず for (初期化式; 継続条件式; 変化式)
の形でループを実現することができます。
そして、この形でループを実現することにより、どのようなループであるかが読み手に伝わりやすくなりますし、さらに 初期化式
や 変化式
の書き忘れのバグを防ぎやすくなります。
それに対して while
ループはどうでしょう?
前述の通り、for
ループは while
ループで書き換え可能であり、while
ループを 初期化式
・継続条件式
・変化式
を用いて記述すると下記のようになります。
初期化式;
while (継続条件式) {
繰り返す処理
変化式;
}
もちろん、これでも for
ループ同様の処理を実現することは可能なのですが、初期化式
・継続条件式
・変化式
が1箇所に集まっていないので、for
ループの時に比べると、読み手からするとどういうループであるかが読み取りづらくなります。
また、初期化式
と while
の間に処理があったり、繰り返す処理
が何行にも渡って記述されていると、初期化式
・継続条件式
・変化式
が離れてしまって余計に読み取りづらくなります。
何より、上記の書き方だと 初期化式
や 変化式
を書き忘れることがあり、意図した通りにループが動作させられないようなことも結構あります。少なくとも私はこのバグを何回も経験してきました…。もちろんすぐに原因には気付くことは出来るのですが、再度コンパイル&実行して動作確認を行う必要があるため手間がかかり、開発効率も低下します。
こういった理由から、ループを実行する前にループ回数が分かっている場合は、for (初期化式; 継続条件式; 変化式)
と1箇所にまとめてループの情報を記述できる for
ループの方を使うことの方が多いと思います。
スポンサーリンク
while
ループの使いどころ
ただ、ループを開始する時点で必要なループ回数が分からない場合も多々あります。
例えば、何回か例に挙げた、ユーザーからの入力を繰り返し受け付け、負の値が入力されたらループを抜けるような処理を実現しようと思えば、for
ループを利用した場合は下記のように記述することになります(入力された値の2倍の値を表示するようにしています)。
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 (継続条件式) {
繰り返す処理
}
例えば先ほどの for
ループの例を 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
の方が簡潔に記述できるからです。
まとめ
このページでは、for
と while
の使い分けについて解説しました!
for
と while
の使い分けについては一般的な明確なルールはありませんが、下記で使い分けることが多いです。
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
を使った方が良いと言った方が良いかもしれません。
いずれにせよ、重要なのは「読みやすくバグりにくい」ソースコードを書くことだと思います。
ループの継続条件が複数存在するような場合なども、そのまま上記の考え方が当てはまらない場合があると思いますが、その時は「読みやすくバグりにくい」ソースコードにするにはどうすれば良いかを考えながら、for
と while
を使い分けるようにしましょう!
また、ページの最初でも紹介したように、C言語にはループの実現方法として do while
も用意されています。
while
と do while
の使い分けについては下記で解説していますので、こちらも是非読んでみてください!
オススメの参考書(PR)
C言語学習中だけど分からないことが多くて挫折しそう...という方には、下記の「スッキリわかるC言語入門」がオススメです!
まず学習を進める上で、参考書は2冊持っておくことをオススメします。この理由は下記の2つです。
- 参考書によって、解説の仕方は異なる
- 読み手によって、理解しやすい解説の仕方は異なる
ある人の説明聞いても理解できなかったけど、他の人からちょっと違った観点での説明を聞いて「あー、そういうことね!」って簡単に理解できた経験をお持ちの方も多いのではないでしょうか?
それと同じで、1冊の参考書を読んで理解できない事も、他の参考書とは異なる内容の解説を読むことで理解できる可能性があります。
なので、参考書は2冊持っておいた方が学習時に挫折しにくいというのが私の考えです。
特に上記の「スッキリわかるC言語入門」は、他の参考書とは違った切り口での解説が豊富で、他の参考書で理解できなかった内容に対して違った観点での解説を読むことができ、オススメです。題名の通り「なぜそうなるのか?」がスッキリ理解できるような解説内容にもなっており、C言語入門書としてもかなり分かりやすい参考書だと思います。
もちろんネット等でも色んな観点からの解説を読むことが出来ますので、分からない点は別の人・別の参考書の解説を読んで解決していきましょう!もちろん私のサイトも参考にしていただけると嬉しいです!
入門用のオススメ参考書は下記ページでも紹介していますので、こちらも是非参考にしていただければと思います。
https://daeudaeu.com/c_reference_book/