4日目:繰り返し処理

for・while・do〜while を使ったループ処理の基本を学びましょう

日数: 0 1 2 3 4 5 6 7

繰り返し処理

アルゴリズムと繰り返し処理

コンピュータのプログラムの処理には、順次処理(じゅんじしょり)分岐処理(ぶんきしょり)があることはすでに述べました。ここでは、もう一つの処理である繰り返し処理について説明します。

コンピュータのプログラムの処理のことを、一般にアルゴリズムと言いますが、アルゴリズムはこの3つの処理によって記述されています。ここでは、C#における繰り返し処理の記述方法について説明します。

for 文

サンプルプログラム

まず手始めに、繰り返し処理の最も基本的な処理である for(フォー) 文について学んでいきましょう。for 文は、{} で囲まれた処理を、指定した条件が満たされる間繰り返す命令です。繰り返し処理をループ処理とも言うことから、for 文による繰り返しを for ループとも呼びます。for ループは C# のプログラムの中で最もよく使われる処理の一つです。しっかり覚えておきましょう。

プロジェクト: Sample401 / ファイル名: Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Sample401
{
    class Program
    {
        static void Main(string[] args)
        {
            for (int i = 1; i <= 5; i++)
            {
                Console.Write(i + " ");
            }
            Console.WriteLine();
        }
    }
}
実行結果
1 2 3 4 5

for 文の書式

プログラムの結果を見ると、for 文の {} に囲まれた部分が5回実行され、i が 1 から 5 に1つずつ増加していることがわかります。for 文の書式は以下のとおりです。

for 文の書式
for (初期化処理 ; 条件式 ; 増分処理)
{
処理
}

Sample401 にあてはめると、初期化処理で i = 1 としているので最初は i の値が 1 から始まります。条件式は i <= 5 なので、i が 5 以下の場合は処理が継続されます。増分処理には i++ と書いていますが、これはインクリメントと言って、i の値を 1 増加させる処理です。

つまり、このfor文は「i = 1 から始めて、i を1つずつ増やしながら i が 5 以下ならば {} 内の処理を実行し、i が 5 より大きくなればループを抜ける」という処理になります。

forループの仕組み

図4-1. for ループの仕組み

インクリメント・デクリメント

for 文では、インクリメントおよびデクリメントという処理をよく使います。デクリメントとはインクリメントの反対で、変数の値を 1 減らす処理です(表4-1)。

表4-1:インクリメント・デクリメントの処理一覧
演算子呼び名意味該当する演算
i++インクリメント(後置)変数の値を 1 増加させるi = i + 1; / i += 1;
++iインクリメント(前置)変数の値を 1 増加させるi = i + 1; / i += 1;
i--デクリメント(後置)変数の値を 1 減少させるi = i - 1; / i -= 1;
--iデクリメント(前置)変数の値を 1 減少させるi = i - 1; / i -= 1;

前置と後置の違い

i++++ii----i はそれぞれまったく同じ意味であるように見えますが、前置(ぜんち)後置(こうち)には違いがあります。例えば、以下のような処理を行うと、

前置・後置の違いの例
int a1=1, b1=1, c1=1, d1=1;
int a2, b2, c2, d2;
a2 = a1++; // 後置:まず a2 = a1 を代入してから a1 を増加
b2 = ++b1; // 前置:まず b1 を増加してから b2 = b1 を代入
c2 = c1--; // 後置:まず c2 = c1 を代入してから c1 を減少
d2 = --d1; // 前置:まず d1 を減少してから d2 = d1 を代入

結果は次のようになります。

a1=2 b1=2 c1=0 d1=0
a2=1 b2=2 c2=1 d2=0

前置は演算の完了後に左辺へ代入されるのに対し、後置は代入の後に演算を行います。インクリメントを例にまとめると以下のとおりです。

インクリメントの前置・後置の処理内容
a = i++; ← a = i; i += 1; と同じ
a = ++i; ← i += 1; a = i; と同じ

様々な for 文の記述方法

基本的な for 文の使い方がわかったところで、様々な記述方法を見てみましょう(表4-2)。

表4-2:for 文の記述方法の例
No.記述方法実行結果説明
for (int i = 0; i < 5; i++)0 1 2 3 40 から始め、5 になるとループを抜ける
for (int i = -2; i <= 2; i++)-2 -1 0 1 2-2 から 2 まで 1 つずつ増加させる
for (int i = 0; i < 10; i += 2)0 2 4 6 8値を 2 つずつ増加させる
for (int i = 5; i >= 1; i--)5 4 3 2 15 から始め、値を 1 ずつ減少させる
for (int i = 2; i >= -2; i--)2 1 0 -1 -22 から -2 まで 1 つずつ減少させる
for (int i = 12; i > 0; i -= 3)12 9 6 3値を 3 つずつ減少させる。0 になるとループを抜ける

この例では int 型の場合を取り上げましたが、他のデータ型でも for ループを利用することは可能です。

for の二重ループ

サンプルプログラム

次に、for の二重ループ(for のネスト)を紹介します。これは for ループの中にさらに for ループを記述する処理で、よく用いられるテクニックです。

プロジェクト: Sample402 / ファイル名: Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Sample402
{
    class Program
    {
        static void Main(string[] args)
        {
            //  for の二重ループ
            for (int i = 1; i <= 2; i++)
            {
                for (int j = 1; j <= 3; j++)
                {
                    int k = i + j;
                    Console.Write(i + "+" + j + "=" + k + " ");
                }
                Console.WriteLine();
            }
        }
    }
}
実行結果
1+1=2 1+2=3 1+3=4
2+1=3 2+2=4 2+3=5

多重ループ

このプログラムでは、外側の変数 i のループが内側の変数 j のループを繰り返しています。3回 × 2回で、合計6回のループが実現しています(表4-3)。

表4-3:i, j の関係性
iji+j
112
123
134
213
224
235

このようにして、3重・4重のループを作ることも可能です。ただし、現実的に最も多く使われるのは2重ループ程度です。

while 文

サンプルプログラム

ループ処理を行うのは for 文だけではありません。while(ホワイル) 文を用いることによっても実現できます。

プロジェクト: Sample403 / ファイル名: Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Sample403
{
    class Program
    {
        static void Main(string[] args)
        {
            int i = 0;
            while (i <= 5)
            {
                Console.Write(i + " ");
                i++;
            }
            Console.WriteLine();
        }
    }
}
実行結果
0 1 2 3 4 5

while 文の書式

while の書式
while (条件式)
{
処理
}

while 文は、() 内の条件が成り立つ間は {} 内の処理を繰り返します。Sample403 では、i <= 5 という条件が成り立っている間、中の処理が繰り返されます。13行目で i を 0 で初期化し、ループ内で i の値を表示しながら i++ で値を増加させます。i が 6 になると i <= 5 が偽となり、ループから抜けます。

whileループの仕組み

図4-2. while ループの仕組み

表4-4:i と条件の関係性
i条件式真/偽
00 <= 5
11 <= 5
22 <= 5
33 <= 5
44 <= 5
55 <= 5
66 <= 5偽(ループ終了)

このサンプルは Sample401 と同等の処理ですが、for 文と違うのは、インクリメントの処理や初期値の設定がループの外(または内部)に分かれている点です。

do〜while 文

サンプルプログラム

ループ処理の3つ目として、do〜while(ドゥ・ホワイル) 文について説明します。

プロジェクト: Sample404 / ファイル名: Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Sample404
{
    class Program
    {
        static void Main(string[] args)
        {
            int i = 0;
            do
            {
                Console.Write(i + " ");
                i++;
            } while (i <= 5);
            Console.WriteLine();
        }
    }
}
実行結果
0 1 2 3 4 5

do〜while 文の書式

実行結果は Sample401・Sample403 と変わりません。do〜while 文の書式は以下のとおりです。

do〜while の書式
do
{
処理
} while (条件式); ← while の後にセミコロンが必要

do〜while 文は、条件式の判定が後ろについているだけで、while 文とほぼ同じ働きをします。ただし、while の後に ;(セミコロン)が必要な点に注意してください。

do〜whileループの仕組み

図4-3. do〜while ループの仕組み

while 文との違い

「while と do〜while はどう違うのか?」という点について、以下のサンプルで確認してみましょう。

プロジェクト: Sample405 / ファイル名: Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Sample405
{
    class Program
    {
        static void Main(string[] args)
        {
            int i, num;
            num = 1;
            //  while ループで実行
            Console.Write("whileで実行:");
            i = 1;
            while (i < num)
            {
                Console.Write("*");
                i++;
            }
            Console.WriteLine();
            //  do~while ループで実行
            Console.Write("do~whileで実行:");
            i = 1;
            do
            {
                Console.Write("*");
                i++;
            } while (i < num);
            Console.WriteLine();
        }
    }
}
実行結果
whileで実行:
do~whileで実行:*

while の方は何も表示されていませんが、do〜while の方は1つだけ表示されています。これは、while の場合 i の値がもともと条件を満たしていないため {} 内の処理が一切実行されないのに対し、do〜while の場合はまず {} の処理を実行してから条件判定を行うため、条件を満たしていなくても最低1回は処理が実行されることによるものです。

無限ループ

サンプルプログラム

最後に、ループ処理でよく出てくる無限ループについて説明しましょう。無限ループとは、その名のとおり「際限なく繰り返されるループ」です。ここでは while 文を用いたサンプルを紹介します。

プロジェクト: Sample406 / ファイル名: Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Sample406
{
    class Program
    {
        static void Main(string[] args)
        {
            //  乱数の初期設定
            Random rnd = new Random();
            Console.WriteLine("6が出たら終了");
            //  無限ループ
            while (true)
            {
                int dice = rnd.Next(1, 7);  //  1以上7未満の乱数を発生させる(1〜6)
                Console.WriteLine(dice);
                if (dice == 6)
                {
                    break;      //  ループから抜ける
                }
            }
            Console.WriteLine("終了");
        }
    }
}
実行結果(例)
6が出たら終了
2
2
3
6
終了

プログラムを実行すると「6が出たら終了」と出力され、1〜6の乱数が次々と出力されます。1〜5の数値が出るとそのまま繰り返されますが、6が出ると終了します。

乱数

C# で乱数を発生させる際には、まず以下のように乱数オブジェクトの生成を行います。オブジェクトについては 6日目で詳しく説明します。ここでは乱数を発生させるための手続きだと思ってください。

乱数オブジェクトの生成
Random rnd = new Random();

続いて、生成したオブジェクトから乱数を発生させます。

乱数を発生させる
int dice = rnd.Next(1, 7); // 1以上7未満の乱数を発生させる(1〜6)

Next() の () 内に、発生させる乱数の範囲を指定します。最初の「1」は最小値、二つ目の「7」は「7未満」を意味します。つまり Next(1, 7) とすることで、1〜6の乱数を発生させることができます。

無限ループと break

while(true) とすると、条件式が常に真(true)となるため、処理は無限に繰り返されます。ただし、break(ブレイク) があるとループから抜けることができます。無限ループは for 文や do〜while でも実現でき、いずれも break で抜けることができます。

⚠️ 無限ループには、意図して使うものと、誤って作ってしまうものがあります。意図せず無限ループが発生した場合は、強制的にプログラムを終了させる必要があります。

以上で、順次処理分岐処理繰り返し処理というアルゴリズムの三大要素を記述する方法について説明しました。次からは、より複雑なプログラムを作るために必要な知識を身につけていきましょう。

練習問題 4 へ →