- バックアップ一覧
- 差分 を表示
- 現在との差分 を表示
- ソース を表示
- 授業/C言語基礎/for文 へ行く。
- 1 (2015-09-28 (月) 13:12:40)
- 2 (2015-09-28 (月) 13:18:29)
- 3 (2015-10-12 (月) 10:27:31)
- 4 (2015-10-18 (日) 16:49:51)
- 5 (2015-10-19 (月) 11:44:11)
- 6 (2015-10-19 (月) 22:51:37)
- 7 (2015-10-20 (火) 19:40:56)
- 8 (2015-10-20 (火) 22:41:30)
- 9 (2015-10-21 (水) 11:12:02)
- 10 (2015-10-23 (金) 09:22:53)
- 11 (2015-10-23 (金) 10:51:26)
- 12 (2015-10-29 (木) 10:51:25)
- 13 (2015-10-29 (木) 10:51:25)
- 14 (2016-10-20 (木) 16:28:33)
- 15 (2016-10-22 (土) 22:04:53)
- 16 (2016-10-23 (日) 06:15:19)
- 17 (2016-10-23 (日) 06:15:19)
- 18 (2016-12-25 (日) 11:51:36)
同じ処理を繰り返し行う †
コンピューターは、同じ処理を繰り返し行うことが得意です。
次のようなプログラムを考えてみましょう。
Hello World!と10回画面に表示する
これをそのままプログラムにすると、次のようになります。
printf("Hello World!\n"); printf("Hello World!\n"); printf("Hello World!\n"); printf("Hello World!\n"); printf("Hello World!\n"); printf("Hello World!\n"); printf("Hello World!\n"); printf("Hello World!\n"); printf("Hello World!\n"); printf("Hello World!\n");
全く同じ命令が10回繰り返されています。 (コメント部分はコンパイル時に無視されます。)
for文は、このような同じ処理を繰り返し行うことができます。
for文は、次の形をしています。
int i; for (i = 1; i <= 繰り返し回数; i++) { 処理 }
ここで、++ は増分演算子(インクリメント演算子)です。 後で詳しく説明します。
for文を使って上のプログラムを書くと、次のようになります(プログラム1)。
int i; for (i = 1; i <= 10; i++) { printf("Hello World!\n"); }
これを実行すると、次のようになります。
luna% a.out Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!
演習1 †
プログラム1を作成し、実行結果を確認せよ。
カウント変数 †
for文で使われている変数 i は、繰り返し回数をカウントするのに使われています。 繰り返し回数をカウントしているので、カウント変数と呼ばれます。 カウント変数の名前は、i でなくても構いません。
上のプログラムに、変数 i の値を出力する命令を追加します(プログラム2)。
int i; for (i = 1; i <= 10; i++) { printf("%d\n", i); printf("Hello World!\n"); }
これを実行すると、次のようになります。
luna% a.out 1 Hello World! 2 Hello World! 3 Hello World! 4 Hello World! 5 Hello World! 6 Hello World! 7 Hello World! 8 Hello World! 9 Hello World! 10 Hello World!
演習2 †
プログラム1をプログラム2に変更し、実行結果を確認せよ。
増分・減分演算子 †
for文の中で使われている ++ という演算子は、増分演算子(インクリメント演算子)といい、カウント変数 i の値を1増やす演算子です。
増分演算子と同じ仲間に、変数の値を1減らす減分演算子(デクリメント演算子)があります。
優先順位 | 演算子 | 使用例 | 意味 |
2 | ++ | i++ | iの値を1増やす |
++i | |||
−− | i−− | iの値を1減らす | |
−−i |
演算子が変数の前についている場合(前置)と変数の後についている場合(後置)では意味が違いますが、後日詳しく勉強します。
for文 †
上では、for文の形を次のように説明しました。
int i; for (i = 1; i <= 繰り返し回数; i++) { 処理 }
正確に説明すると、for文は次の形をしています。
for (初期化; 繰り返し条件; 更新処理) { 処理 }
if文と同じように、for文の波括弧 { } に含まれる命令文が0または1個のとき、この波括弧を省略することができます。
for文は、次のように実行されます。
- 「初期化」を行う
- 「繰り返し条件」を評価する
- 条件を満たしていれば、波括弧 { } の中の「処理」を行い、最後に「更新処理」を行う
- そうでなければ、for文の次の処理に移る
- 2へ戻る
したがって、カウント関数は1からでなく、0から始めることもできます。 また、カウント関数を1ずつ増やすのではなく、2ずつ増やしたり、1ずつ減らすこともできます。
たとえば、10から0までカウントダウンするプログラムは、次のようになります(プログラム3)。
int i; for (i = 10; i >= 0; i--) { printf("%d\n", i); sleep(1); }
演習3 †
プログラム3を作成し、実行結果を確認せよ。
無限ループと強制停止 †
for文は、条件を満たしている間繰り返し続けますので、条件を満たさないことがないと無限に繰り返しを続けます。 これを無限ループといいます。
たとえば、次のプログラムについて考えてみます(プログラム4)。
int i; for (i = 1; i = 10; i++) { printf("%d\n", i); printf("Hallo World!\n"); }
繰り返し条件の演算子を間違えて、代入演算子にしてしまっています。
繰り返し条件を評価すると、カウント変数に10が代入されます。 このとき、結果が0でないので、条件を満たしていると判断され、波括弧の中の処理と更新処理がおこなわれます。 更新処理によってカウント変数は11になりますが、繰り返し条件を評価すると、カウント変数に10が代入されるため、このfor文が停止することはありません。
このようなとき、コントロール・キーを押しながらCキーを押し、プログラムの実行を強制的に停止させます。 コントロール・キーを押しながらCキーを押す操作を、Ctrl+Cと書くことがあります。
演習4 †
プログラム2をプログラム4に変更し、実行して強制停止せよ。
一度も処理しないfor文 †
for文の繰り返し条件が一度も満たされないとき、for文の波括弧内の処理は一度も実行されません。
たとえば、次のプログラムについて考えてみます(プログラム5)。
int i; for (i = 10; i <= 0; i--) { printf("%d\n"); sleep(1); } printf("\n");
カウントダウンするプログラム(プログラム3)において、繰り返し条件の不等号の向きを間違えてしまっています。
これを実行すると、繰り返し条件が最初から満たされていないので、for文の波括弧内のprintf関数とsleep関数は実行されることなく、for文の後の改行を出力するprintf関数だけが実行されます。
演習5 †
プログラム3をプログラム5に変更し、実行結果を確認せよ。
合計を求める †
繰り返し処理を用いてよく行われることの一つが、合計を求めることです。
1から100までの整数の和を求めることを考えてみます。
そのままプログラムにすると次のようになります。
int sum = 1 + 2 + 3 + 4 + 5 + ... + 99 + 100; printf("%d\n", sum);
もちろん、...の部分も省略せずに書かなければなりませんが、ここでは省略してあります。
この処理は、2を加える、3を加える、4を加える ... という加算の繰り返しだと考えることができます。
そこで、この処理を、次のように同じ命令文の繰り返しの形に直します。
int sum = 1; sum = sum + 2; sum = sum + 3; sum = sum + 4; sum = sum + 5; ... sum = sum + 99; sum = sum + 100; printf("%d\n", sum);
ここで、
sum = sum + 2;
は、右辺の計算をしてから代入が行われるため、変数sumの値に2を加えた結果を変数 sum に代入します。 つまり、変数 sum の値に2を加えます。
加える数をカウント変数 i で表すと、繰り返し行われている加算の処理はすべて
sum = sum + i;
という形で書くことができます。
したがって、加える数をカウント変数とし、カウント変数を2に初期化して100まで繰り返すと、次のようなfor文を使ったプログラムにできます(プログラム6)。
int i, sum = 1; for (i = 2; i <= 100; i++) { sum = sum + i; } printf("%d\n", sum);
これでも間違いではありませんが、普通は、合計を表す変数の値を0に初期化して、最初の数も加えていると考えます。
つまり、
int sum = 0 + 1 + 2 + 3 + ... + 99 + 100; printf("%d\n", sum);
と変形して、次のようなプログラムにします(プログラム7)。
int i, sum = 0; for (i = 1; i <= 100; i++) { sum = sum + i; } printf("%d\n", sum);
これだと、合計を求める範囲が変わったときに、カウント変数の初期値と繰り返し条件のところだけを変えるだけで済みます。 (プログラム6は、sumの初期値も変えなければなりません。)
演習6 †
プログラム7を作成し、実行結果を確認せよ。
複合代入演算子 †
合計を求めるプログラムで出てきたような、変数の値にある値を加えて、その結果をその変数に代入するという処理はよく行われます。
sum = sum + i
このため、算術演算と代入を同時に行う演算子として、複合代入演算子が用意されています。
上の処理の場合、加算用の複合代入演算子 += を使って、次のように書くことができます。
sum += i;
したがって、プログラム7は、次のように書くことができます(プログラム8)。
int i, sum = 0; for (i = 1; i <= 100; i++) { sum += i; } printf("%d\n", sum);
算術演算の複合代入演算子には、次のようなものがあります。
優先順位 | 演算子 | 使用例 | 意味 |
15 | += | a += b | aとbの和をaに代入する(加算代入) |
−= | a −= b | aとbの差をaに代入する(減算代入) | |
*= | a *= b | aとbの積をaに代入する(乗算代入) | |
/= | a /= b | aをbで割ったときの商をaに代入する(除算代入) |
剰余算の複合代入演算子はありません。
演習6 †
プログラム7をプログラム8に変更し、実行結果を確認せよ。
for文のネスト †
for文の中にfor文を入れることをネスト(入れ子構造)といいます。
for文をネストするとき、外側のfor文と内側のfor文では異なるカウント変数を使用します。
つぎのプログラムは、九九の計算をします(プログラム9)。
#include <stdio.h> #include <stdlib.h> #include <time.h> int main(void) { int i, j, k, a, cnt; srand((unsigned int) time(NULL)); cnt = 0; for (k = 1; k <= 10; k++) { i = rand() % 99 + 1; j = rand() % 99 + 1; printf("第%d問: %d + %d = \n", k, i, j); scanf("%d", &a); if (a == i + j) { cnt++; } } printf("%d問正解!\n", cnt); return 0; }
外側のfor文のカウント変数が i、内側のfor文のカウント変数が j です。
このプログラムを実行すると、次のようになります。
int i, j, k; for (i = 1; i <= 9; i++) { for (j = 1; j <= 9; j++) { k = i * j; printf("%d * %d = %d\n", i, j, k); } }
ネストされたfor文では、外側のfor文が[math]N[/math]回、内側のfor文が[math]M[/math]回繰り返されるとき、内側のfor文の波括弧内の処理は全部で[math]N \times M[/math]回繰り返されます。
プログラム9の改行を少なくして、表の形で出力すると、次のようになります(プログラム10)。
luna% a.out 1 * 1 = 1 1 * 2 = 2 ... 1 * 9 = 9 2 * 1 = 2 2 * 2 = 4 ... 2 * 9 = 18 3 * 1 = 3 3 * 2 = 6 ... 9 * 8 = 72 9 * 9 = 81
内側のfor文では改行せずに、外側のfor文だけで改行しているところがポイントです。
このプログラムを実行すると、次のようになります。
int i, j, k; for (i = 1; i <= 9; i++) { for (j = 1; j <= 9; j++) { k = i * j; printf("%3d", k); } printf("\n"); }
for文のネストを使うと、次のようなこともできます(プログラム11)。
luna% a.out 1 2 3 4 5 6 7 8 9 2 4 6 8 10 12 14 16 18 3 6 9 12 15 18 21 24 27 4 8 12 16 20 24 28 32 36 5 10 15 20 25 30 35 40 45 6 12 18 24 30 36 42 48 54 7 14 21 28 35 42 49 56 63 8 16 24 32 40 48 56 64 72 9 18 27 36 45 54 63 72 81
内側のfor文の繰り返し回数が、外側のfor文のカウント変数の値になっています。 つまり、外側のfor文は「内側のfor文と改行だけを出力するprintf関数」を10回繰り返し実行し、内側のfor文は「* を出力するpriftf関数」を外側のカウント変数の回数だけ繰り返し実行します。
このプログラムを実行すると、次のようになります。
int i, j; for (i = 1; i <= 10; i++) { for (j = 1; j <= i; j++) { printf("*"); } printf("\n"); }
演習7 †
プログラム9、プログラム10、プログラム11を作成し、実行結果を確認せよ。