Lesson 3

プログラムの流れの繰り返し

Lesson 3 Chapter 1
do文

do文

do (ドゥ)文は、条件式を判定して文を繰り返す構文です。do文は繰り返しを少なくとも1回実行した後に条件式の判定を行います。なので、条件式に関わらず、文を最低1回実行します。do文は下記のように記述します。文を先に書いて「while」(ワイル)の後に条件式を書きます。

do文の書き方(文が1つの場合)
do 文; while (式);

文が複数ある場合は、ブロックを使って書きます。ブロック内の文はインデントします。

do文の書き方(文が複数の場合)
do {
  文; 
  …
} while (式);

3_1.png

do文の処理順は以下のようになります。
1. 文を実行する
2. 式を評価する
3. 評価結果が「真」の場合、もう一度、文を実行する
4. 評価結果が「偽」の場合、処理を終了する
では、do文を使った処理をコーディングしてみましょう。整数を1から5まで表示するプログラムを書きます。

do.c
#include <stdio.h>
int main(void) {
  int i = 1;

  do printf("%d", i);
  while (i++ < 5);
  
  i = 1;
  puts("");
  
  do {
    printf("%d", i);
  } while (i++ < 5);
  
  return 0;
}
実行結果
do.exe
12345
12345

do文では、括弧()内の条件式が「真」である間は、繰り返し処理を実行します。1回の繰り返しごとにインクリメント処理(++演算子)によって変数iの値が1つずつ増えていき、その度に条件判定が行われます。変数iの値が1から始まり、5までの間は繰り返されるので実行結果のようになります。変数iが6になった時点で、繰り返し条件を満たさなくなり、do文を抜けます。

++演算子とは

「do.c」の中で見慣れない「i++」というコードが書かれています。これは「増分演算子」と呼ばれ、変数iの値をインクリメント(i = i + 1)します。詳細については後述のChapter「増分演算子と減分演算子」で解説します。

Lesson 3 Chapter 2
while文

while文

「while」(ワイル)文は、条件式が「真」である限り、ブロックの中の繰り返し処理を実行し続けます。構文は以下のようになります。

while文の書き方(文が1つの場合)
while (式) 文;

繰り返し処理したい文が複数ある場合は、ブロックを使って書きます。ブロック内の文はインデントします。

while文の書き方(文が複数の場合)
while (式) {
  文; 
  …
}

3_2.png

while文の処理順は以下のようになります。
1. 式を評価する
2. 評価結果が「真」の場合、もう一度、文を実行する
3. 評価結果が「偽」の場合、処理を終了する
式が最初から「偽」の場合は、繰り返し処理は実行しません。
では、while文を使って整数を1から5まで表示するプログラムを書いてみましょう。

while.c
#include <stdio.h>
int main(void) {
  int i = 0;

  while (i++ < 5) printf("%d", i);
  
  i = 0;
  puts("");
  
  while (i++ < 5) {
    printf("%d", i);
  };
  
  return 0;
}
実行結果
while.exe
12345
12345

while文では、括弧()内の条件式が真である間は、繰り返し処理を実行し続けます。1回の繰り返しごとにインクリメント処理(増分演算子)によって変数iの値が1ずつ増えていき、その度に条件判定が行われます。変数iの値が1から始まり、5までの間は繰り返されるので実行結果のようになります。変数iが6になった時点で、繰り返し条件を満たさなくなり、while文を抜けます。

増分演算子と減分演算子

「増分演算子」と「減分演算子」は、繰り返し文と一緒に使うことが多い演算子です。繰り返しを行うときに、変数に1を加算する、変数から1を減算するといった処理が多いからです。「増分演算子」と「減分演算子」には「前置」と「後置」があり、表にまとめると以下の4種類になります。

演算子 名称
++a 前置増分演算子
a++ 後置増分演算子
--a 前置減分演算子
a-- 後置減分演算子

「前置」と「後置」について解説します。「前置」は、
1. 対象を+1または-1する
2. そのあと式の値を生成する
と考えます。コードで書くと以下のようになります。

前置(++aの場合)
int a = 1;
int b;
a = a + 1; ← 対象を+1する
b = a;  ← そのあと式の値を生成する

式の値は加算後または減算後の値が格納されます。 変数aと変数bの値は両方「2」になります。 逆に「後置」は、
1. 式の値を生成する
2. そのあと対象を+1または-1する
と考えます。式の値は加算前または減算前の値が格納されます。 コードで書くと以下のようになります。

後置(a++の場合)
int a = 1;
int b;
b = a;  ← 式の値を生成する
a = a + 1; ← そのあと対象を+1する

変数aの値は「2」、変数bの値は「1」になります。 実際にコードを書いて確認してみましょう。

zenchi.c
#include <stdio.h>
int main(void) {
  int a = 1;
  int b = ++a;
  
  puts("【前置(++a)】");
  printf("a=%d\n", a);
  printf("b=%d\n", b);
  
  a = 1;
  b = a++;
  
  puts("【後置(a++)】");
  printf("a=%d\n", a);
  printf("b=%d\n", b);
 
  a = 1;
  b = --a;
  
  puts("【前置(--a)】");
  printf("a=%d\n", a);
  printf("b=%d\n", b);
 
  a = 1;
  b = a--;
  
  puts("【後置(a--)】");
  printf("a=%d\n", a);
  printf("b=%d\n", b); 
 
  return 0;
}
実行結果
while.exe
【前置(++a)】
a=2
b=2
【後置(a++)】
a=2
b=1
【前置(--a)】
a=0
b=0
【後置(a--)】
a=0
b=1

「前置」と「後置」の使い方を正しく理解しないと、プログラムが期待通りに動作しないので、加算と減算のタイミングをしっかり覚えましょう。

インクリメントとデクリメント

数字に1加算することをインクリメント、1減算することをデクリメントといいます。 一般的に「変数Aをインクリメントする」、「変数Bをデクリメントする」といった表現をします。「++」を「インクリメント演算子」、「--」を「デクリメント演算子」と呼ぶこともあります。

do文とwhile文の違い

do文はwhile文に似ていますが、繰り返しを続けるかどうかを判定するタイミングが異なります。while文は繰り返しを実行する前に判定を行いますが、do文は繰り返しを1回実行した後に判定を行います。そのため、繰り返しの条件が最初から「偽」の場合は、while文は繰り返しを1回も実行しません。一方、do文は繰り返しを少なくとも1回は実行します。

複合代入演算子

「複合代入演算子」は、計算と代入を同時に行う演算子です。順を追って説明すると 、
1. aとbの間で計算を行う 2. 結果をaに代入する 上記の処理を同時に行います。「複合代入演算子」の種類について確認します。

演算子 名称 書き方 処理
+= 加算代入演算子 a += b aとbの和をaに代入
-= 減算代入演算子 a -= b aとbの差をaに代入
*= 乗算代入演算子 a *= b aとbの積をaに代入
/= 除算代入演算子 a /= b aとbの商をaに代入
%= 剰余代入演算子 a %= b aとbの割った余りをaに代入

「a += b」は「a = a + b」とやっている処理は同じです。簡潔にコードを書きたい場合は「複合代入演算子」でコードを書きましょう。では、scanf関数で入力した整数と整数の5を「加算代入演算子」で処理するプログラムを確認します。

fukugo.c
#include <stdio.h>
int main(void) {
	int a;
	puts("整数を入力してください");
	scanf("%d", &a);

	printf("a += 5 は %d\n", a += 5);

	puts("もう一度同じ整数を入力してください");
	scanf("%d", &a);

	printf("a = a + 5 は %d\n", a = a + 5);

	return 0;
}
fukugo.exe
整数を入力してください
10
a += 5 は 15
もう一度同じ整数を入力してください
10
a = a + 5 は 15

どちらも結果は「15」であることが分かります。

Lesson 3 Chapter 3
for文

for文

C言語にはいくつかの繰り返し文がありましたが「for」 (フォー)文もよく使用される繰り返し文の1つです。「for」文は回数が決まっている繰り返し処理や、回数が決まっていない繰り返し処理にも応用できます。繰り返し処理の度に評価する式を書けることが「for」文の特徴です。
構文は以下のように書きます。

for文の書き方(文が1つの場合)
for (初期化式; 条件式; 変化式) 文;

文が複数ある場合は、ブロックを使って書きます。ブロック内の文はインデントします。

for文の書き方(文が複数の場合)
for (初期化式; 条件式; 変化式) {
  文; 
  …
};

for文の処理の流れは以下のようになります。 1. 初期化式を実行する 2. 条件式の評価を行う 3. 評価の結果が「真」の場合、文を実行する 4. 変化式を実行する 5. 2の処理に戻る 処理3で評価が「偽」の場合はfor文を抜けます。実際にfor文を使ってみましょう。Oから5までの整数を繰り返し処理を使って表示するプログラムを書きます。

for1.c
#include <stdio.h>
int main(void) {

  for (int i = 0; i <= 5; i++) printf("%d", i);
  
  puts("");
  
  for (int i = 0; i <= 5; i++) {
    printf("%d", i);
  };
  
  return 0;
}
実行結果
for1.exe
12345
12345

入れ子となったfor文

Lesson2でif文の「入れ子」を学習しました。今回はfor文の「入れ子」について学習します。繰り返しの中に繰り返し処理を書いたプログラムのことを「多重ループ」(タジュウループ)と呼びます。2次元の表を表示したい場合に、多重ループが使用されることがあります。では、掛け算の九九の一覧を表示するプログラムを考えます。頭の中でコードを組み立て、どのようにコーディングすれば九九を表示できるか、イメージしてみましょう。

for2.c
#include <stdio.h>
int main(void) {
  for (int i = 1; i <= 9; i++) {
    for (int j = 1; j <= 9; j++) {
      printf("%d ", i * j);
    }
    puts("");
  }
  return 0;
}
実行結果
for2.exe
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文は整数の1から9まで繰り返し処理を行うfor文です。その内側は、同様に整数の1から9まで繰り返し処理を行うfor文を書きます。そのあと「i * j」を表示してiとjを乗算した結果を表示します。変数iの値が1からスタートして変数jの繰り返し処理の中で1を受け取り、1から9まで乗算を行います。これで1行目の1の段が表示されます。内側のfor文を抜けたあと、puts関数を使って改行を行います。その後、外側の繰り返しに戻り、次は2の段、3の段と計算結果が表示されます。

Lesson 3 Chapter 4
プログラムの流れを変化させる

break文

switch文のChapterで登場したbreak文ですが、繰り返し処理の中でも使用される場合があります。繰り返し処理を行っている途中で、ある条件を満たした時に処理を抜けるケースなどです。処理を抜けたい部分に「break;」と記述することで繰り返し処理から抜けることができます。for文を使用して、1から10までの整数を表示する処理の途中で、条件を満たした時にfor文から抜けるプログラムを書いてみましょう。

break.c
#include <stdio.h>
int main(void) {
    int a;
    puts("整数を入力してください");
    scanf("%d", &a);

    for (int i = 1; i <= 10; i++) {
        printf("%d\n", i);
        if (i == a) {
            puts("繰り返し処理から抜けます");
            break;
        }
    }
    return 0;
}
実行結果
break.exe
整数を入力してください
5
1
2
3
4
5
繰り返し処理から抜けます

continue文

break文は強制的に繰り返し処理から抜ける構文でした。「continue」(コンテニュー)文は、指定した条件を満たした場合に、その繰り返しを終了して、次の繰り返し処理を実行する構文になります。

continue文の書き方
if (式) continue;

continue文を使って、繰り返し処理が偶数回の場合はスキップ、次の繰り返し処理を実行するプログラムを書いてみましょう。

continue.c
#include <stdio.h>
int main(void) {
    for (int i = 1; i <= 10; i++) {
        if (i % 2 == 0) continue;
        printf("%d\n", i);
    }
    return 0;
}
実行結果
continue.exe
1
3
5
7
9

goto文

goto (ゴートゥー)文は、指定したジャンプ先に飛ぶ機能です。多重ループの終了や、エラー処理などに使用されます。goto文は次のように書きます。

goto文の書き方
goto ラベル;

「ラベル」はgoto文のジャンプ先を示します。「ラベル」は変数名と同様に名前をつけることが可能です。「ラベル」は文の前に書きます。

ラベルの書き方
ラベル: 文;

多重ループのコーディングで使用した、掛け算の九九を表示するプログラムを流用して、8の段の「8 * 5」の時にgoto文を使用し、多重ループを終了するプログラムを書いてみましょう。

goto.c
#include <stdio.h>
int main(void) {
  for (int i = 1; i <= 9; i++) {
    for (int j = 1; j <= 9; j++) {
      printf("%d ", i * j);
      if(i == 8 && j == 5) goto end;
    }
    puts("");
  }
end: 
  puts("多重ループを終了しました");

  return 0;
}
実行結果
goto.exe
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 多重ループを終了しました

goto文を多用して、プログラムの中で処理がぐちゃぐちゃになったコードは「スパゲッティコード」と呼ばれています。他人や書いた本人が読んでもわかりづらく、バグ(エラー)などの原因になってしまうこともあり、goto文の使用は敬遠されがちです。プログラムを書くときは、goto文の多用は控えましょう。