C言語編 第15章 同じ処理を繰り返す(for文)

先頭へ戻る

この章の概要

この章の概要です。


for文

C言語には3種類のループ構文があります。前章で解説した while、この章で解説する for、そして次の章で解説する do-while です。

実はどれか1つあれば、どんなループでも作れます。それなのに3種類も用意されているのは、場合によって向き・不向き(例えば、ソースコードの書きやすさ)があるからです。for文は、3つのループ文の中で最も高機能なループです。

for文の構造は次のようになっています。

for( 初期設定式; 条件式; 再設定式 ){
    ループさせる処理
}

「初期設定式」は、処理が初めて for文に差し掛かったときに、1度だけ実行される式です。ここで、ループを始める前の準備を行います。

「条件式」は、while文と同じで、真のときにループし、偽のときに for文全体を終了させます。ループが終了した場合、for文の後ろにある処理へ進みます。

「再設定式」は、処理が「ループさせる処理」の終端まで終了したときに実行される式です。言い換えると、1回分のループを終える度に実行される式ということです。

実行される処理の順序を整理すると、次のようになります。

  1. 「初期設定式」を実行。2へ
  2. 「条件式」を調べる。「真」なら3へ。「偽」なら6へ
  3. 「ループさせる処理」を実行する。4へ
  4. 「ループさせる処理」が全て終了したら5へ
  5. 「再設定式」を実行。2へ戻る
  6. for文を終了させて、次の処理へ進む

初回の時点で条件式が偽になるとしても、「初期設定式」の部分だけは実行されることに注意してください。

では実際の使用例を確認しましょう。前章のサンプルプログラムを、for文で書き変えてみます。

#include <stdio.h>

int main(void)
{
    char c;
    char str[20];
    int i;

    puts( "1文字入力してください。" );
    fgets( str, sizeof(str), stdin );
    sscanf( str, "%c", &c );

    /* 10回出力する */
    for( i = 0; i < 10; ++i ){
        printf( "%c\n", c );
    }

    return 0;
}

実行結果:

1文字入力してください。
y
y
y
y
y
y
y
y
y
y
y

標準入力から受け取った文字を 10回表示するプログラムです。注目すべき箇所は、for文の部分だけです。

while文のときのサンプルでは、変数count を作り、ループ回数を数えました。for文を使う場合は、こういった変数の管理を、for文の仕組みの中で行うことが多いです。具体的には、i という名前の変数がそれです。

この妙に短い名前は、古くから慣例的に使われており、for文を使って何かをカウントする変数の名前として、非常によく使われています。なお、ループの内側にループがあるような構造なら、内側ではアルファベットを1つ進めて、変数j を使います。

C99 からは、「for (int i = 0; i < 10; ++i )」のように、「初期設定式」のところで変数を宣言できます。実際、このように書くのが良いスタイルです。

この変数i のように、ループ回数を制御する目的のために用意する変数のことを、ループ制御変数と呼ぶことがあります。i という変数名を、ループ制御変数以外の目的で使うことは極力避けるべきでしょう。

for文の「初期設定式」で、変数i に初期値 0 を与え、「再設定式」で加算します。この「再設定式」の部分ですが、「++i」という見慣れない記述になっています。これについては後述しますが、意味的には「変数i を +1 する」ということです。

あとは、「条件式」の部分で、変数i の値が 10未満であることを確かめるだけです。前章で練習したように、変数の初期値を 10 から始めて、1回ループするたびに 1 ずつ減らしていくスタイルでももちろんできますが、1 ずつ増やしていく方が分かりやすいと言えます。

減らしていく形のプログラムは、練習問題として取っておくことにします。

インクリメント

先ほど登場した「++i」という記述ですが、この意味は「変数i を +1 する」です。ここで「++」をインクリメント演算子と呼びます。また、+1 することをインクリメントと呼びます。

インクリメント演算子には2通りの使い方があり、これがなかなか曲者です。1つは「++i」という記述で、もう1つは「i++」という記述です。両者が違いをもつのは、インクリメントした結果を代入する場合です。

#include <stdio.h>

int main(void)
{
    int num;
    int ans;


    /* ++num の場合の実験 */
    num = 10;
    ans = ++num;
    printf( "%d\n", ans );

    /* num++ の場合の実験 */
    num = 10;
    ans = num++;
    printf( "%d\n", ans );

    return 0;
}

実行結果:

11
10

まったく同じ形で書いた3行分のソースですが、「++num」の場合と「num++」の場合とでは、結果が異なることが分かります。

「++num」のように、変数の前に「++」と書く場合を前置インクリメントと呼び、「まず +1 を行ってから、次へ進む」という意味です。従って、変数num の値がもともと 10 だった場合、まず +1 されて 11 になった後、代入などの次の処理を行います。

「num++」のように、変数の後に「++」と書く場合を後置インクリメントと呼び、「次に行うことを先に行ってから、+1 を行う」という意味です。従って、変数num の値がもともと 10 だった場合、まず 10 のまま代入が行われ、その後で +1 されます。

変数num 自身の値の変化だけを見れば、いずれの場合も 10 から 11 にインクリメントされた訳ですが、代入と組み合わさると、代入される値が変わってくる訳です。「代入」と書いていますが、例えば次のような場合も同じです。

#include <stdio.h>

int main(void)
{
    int num = 10;

    printf( "%d\n", num++ );
    printf( "%d\n", ++num );
    printf( "%d\n", num );

    return 0;
}

実行結果:

10
12
12

関数の実引数として指定することも、結果として代入と同じ意味合いです(関数の仮引数へ代入しているとイメージすれば良い)。このプログラムの実行結果は、なぜこういう結果になるのか、よく理解しておいてください。

インクリメントと代入を組み合わせる記述は、慣れるまで難しいものです。特に、後置インクリメントと代入を行う文で、「代入が先に行われている」というのは、難しく思うでしょう。

なお、代入を行わないのであれば、以下の4つはどれも同じ結果になります。

最後にまた新しい記法が出てきましたが、「+=」は加算と代入を一緒にした演算子で、複合代入演算子と呼ばれます。「num += 2」ならば、「変数num を +2 して、変数num に書き戻します。「+=」と同様に「-=」「*=」「/=」「%=」も使え、それぞれやはり同様の意味を持ちます。これらは「num = num + 2」のような、やや面倒な記述を簡単に書くために用意されています。

for文の「再設定式」においては「++i」よりも「i++」の方が使われているのをよく見かけます。単に慣習的なものですが、C++ というプログラミング言語では、実行効率の面から前置スタイルの方が好まれます。そのため、特に前置と後置のどちらを使うべきか理由がないときは、前置を使うクセを付けておくといいかもしれません。

デクリメント

「+1」をインクリメントと呼ぶのに対して、「-1」をデクリメントと呼びます。「++」と同様に「--」というデクリメント演算子があります。

インクリメントのことを理解できていれば、デクリメントは難しくありません。ただ「++」を「--」に置き換えるだけです。「--num」なら前置デクリメントで、「num--」なら後置デクリメントです。代入との関係性も同様です。


練習問題

問題① 本文中のサンプルプログラム(標準入力から受け取った文字を 10回出力する)で、 for文の部分を、 インクリメントさせる方法ではなく、デクリメントさせる方法で書き換えてください。

問題② 1 から 5 までの整数の合計を求めるプログラムを、for文を使って作成してください。

問題③ 1 から 10 までの整数を小さい方から大きい方へ、ただし奇数だけを出力するようなプログラムを作成してください。 2通りのやり方を考えてみてください。

問題④ 1 から順に数字を2倍、2倍、2倍・・・としていき、それぞれの結果を標準出力へ出力するプログラムを作ってください。 値が 1000 を超えた時点で終了させてください。

問題⑤ 次のプログラムを実行すると、何が出力されるでしょう。

#include <stdio.h>

int main(void)
{
    int i;

    for( i = 0; i < 5; ++i );
        printf( "%d\n", i );

    return 0;
}


解答ページはこちら

参考リンク



更新履歴

'2018/6/5 第18章から練習問題⑤を移動してきて、練習問題⑤とした。

'2018/2/8 全面的に文章を見直し、修正を行った。

'2018/1/31 画面という表現を、標準出力に改めた。

'2010/8/30 誤字の修正。

'2009/4/5 新規作成。



前の章へ (第14章 同じ処理を繰り返す(while文))

次の章へ (第16章 同じ処理を繰り返す(do文))

C言語編のトップページへ

Programming Place Plus のトップページへ


はてなブックマーク Pocket に保存 Twitter でツイート Twitter をフォロー
Facebook でシェア Google+ で共有 LINE で送る rss1.0 取得ボタン RSS
管理者情報 プライバシーポリシー