C++入門/制御

柴田祐樹,東京都立大学,情報科学科
戻る

ここでは,プログラムの処理の順番について説明する.わかりやすいかどうかわからないが,ひとつ日常生活の例を挙げる.

作業を行うには,やること(行動単位)と,その順番の2つを決定しなければならない.例えば,水を飲むにしても,コップに水を入れ,コップを顔の前に持ってきて,口をコップにつける,コップを机に置く.という順で行動単位を実行していかなければ水を飲むことはできない.ちょっと例が悪かったように思うが,先にコップを顔の前に持ってきても水を入れることは困難であることから,この順番が大事だということがわかるだろう.この順番を決めることを,とても大雑把で抽象的であるが,制御とよび,行動の単位を,演算と計算機では言う.順番が致命的となる行動単位の適用順を他にも想像してみてもらいたい.電車が通った後に踏切を締めるという制御は許されないなど,もっと致命的な場面がいくらかあるだろう.

プログラムは前述したものより原始的な,演算と制御を記述したものである.プログラムにおける演算とは,ある対象が与えられたときにその状態を変更する,あるいは新しい対象を生成することを言う.例えば,1, 2 を与えられ,3を生成するのは加算と呼ばれる演算である.制御とは,演算の実行順を決定することである.演算は,C++では人が読める式により表現される.

C++での制御は,基本は上から順に演算を適用し,同じ行については左から順に適用するというものである.同じ式の中では演算子の結合強度に従い演算が制御される.たとえば,(1 + 2)*3では,+ が先に実行されるが,1 + 2 * 3 では,2*3が先に実行される.こうした演算子の適用順を判断することも制御の役目である.更に例を上げれば,a = 1 + 2 という文は,+ (加算演算)を先に実行し,= (代入演算)を次に実行するため,= は + より結合強度が弱い演算子であると言える.C++ では事実 = は演算子として定義されている.

演算の制御は結合規則を明示する ( ) と演算子の結合強度で,変更することができた.これに対し,文の実行順序を制御する方法が別に存在する.本説ではこのうち,while, if という文を紹介する.

まず,if であるが,これは()中の命題が真である場合に,直後に書かれた { } で囲まれた領域内の文の塊を実行するかどうかを決めるために使う.以下に例を示す.

#include <iostream>

int main(){
    int i;
    i = 1;
    if(i < 2){
        std::cout << 2 << char(10);
    }
    if(i > 3){
        std::cout << 3 << char(10);
    }
    return 0;
}

実行結果は次のようになる.c.cppはファイル名で移行同様とする.7行目のみが実行されているとわかる.

hiroki@hiroki-home:~/git/cpp$ g++ c.cpp hiroki@hiroki-home:~/git/cpp$ ./a.out 2

同様に,5行目を,i = 4に変えれば10行目が実行され,i=3にすればどちらも実行されないことを確認できるだろう.次に示すのはwhileの例である.これは()中の命題が真である限り,直後に書かれた { } で囲まれた領域内の文の塊を繰り返す制御を提供する.以下に,10回出力を行うことを可能としたコードの例を示す.

#include <iostream>

int main(){
    int i;
    i = 0;
    while(i < 10){
        std::cout << i << char(10);
        i = i + 1;
    }
    return 0;
}

コンパイルと実行の結果は次のとおりになる.

hiroki@hiroki-home:~/git/cpp$ g++ c.cpp hiroki@hiroki-home:~/git/cpp$ ./a.out 0 1 2 3 4 5 6 7 8 9

i は繰り返し回数を計測するための変数で,while の対象範囲(単にブロックと呼ばれる)の中で一度だけi = i + 1 という更新の文が記載されているため,対象範囲が繰り返されるたびに1増えることになる.そして,i < 10 を満たさなくなった場合に,while の繰り返しは終了する.これはみのり多い結果であろう.はじめの方法では,10回繰り返すためには同じ文を10度書かなければならなかったが,この例では,std::cout は一度だけ記載されているにとどまる.この使い方は,4行目から9行目までまとめて暗記しておく必要がある.

この繰り返し文を使うとき,先程の if も有効な使いみちが出てくる.たとえば,繰り返しのなかで,2回に一度だけ出力したい,という場合は次のようにコードを記載することができる.

#include <iostream>

int main(){
    int i;
    int j;
    i = 0;
    j = 2;
    while(i < 10){
        if(j > 1){
            std::cout << i << char(10);
            j = 0;
        }
        j = j + 1;
        i = i + 1;
    }
    return 0;
}

コンパイルと出力の結果は次の通りになる.

hiroki@hiroki-home:~/git/cpp$ g++ c.cpp hiroki@hiroki-home:~/git/cpp$ ./a.out 0 2 4 6 8

3回,4回に一度出力するコードを考えてみると良い.

以下に条件式の一覧を示す.特に,等しいことを示す演算子が代入演算子=と紛らわしいため,そうとう注意深く見てもらいたい.

いくらか例を示す.例えば,先程と同じ結果を与えるコードは次のようにも書ける.

#include <iostream>

int main(){
    int i;
    int j;
    i = 1;
    j = 2;
    while(i !=10){
        if(j == 2){
            std::cout << i << char(10);
            j = 0;
        }
        j = j + 1;
        i = i + 1;
    }
    return 0;
}

また,i!=10の部分はi<=9でも良い.このようにいろいろな形式で書けるが,普通は繰り返し回数が見える形の,i!=10かi<10と書くのが良いと思う.コードの意図ができるだけ読み取れるように書くことは多くの場面で歓迎される.

繰り返しの継続条件が一箇所でしか判断できないと不便なことがある.原理的にはそれで問題は無いが,コードの可読性を確保する為に,ある程度の柔軟性が文法には求められる.この観点から,break という文が用意されていて,これにより,任意の場所でwhileの繰り返しを中断することができる.以下に使い方の例を示す.

#include <iostream>

int main(){
    int i;
    i = 0;
    while(i < 10){
        std::cout << i << char(10);
        if(i == 4){
            break;
        }
        i = i + 1;
    }
    return 0;
}

このコードでは,8行めのifの範囲にbreakが記載されているため,i==4となった段階で繰り返しが終了する.これにより本来ならiが9になるまで,つまり10回の繰り返しがおこなわれるところが,5回の繰り返しで終了する.以下に実行結果を示す.

hiroki@hiroki-home:~/git/cpp$ g++ c.cpp hiroki@hiroki-home:~/git/cpp$ ./a.out 0 1 2 3 4

繰り返しが5回に減っていることを確認できる.

課題

練習問題1

1, 2, ..., 1000の和を計算するコードを繰り返しにより作成せよ.ただし乗算を使ってはならない.

回答

練習問題1: control-ans.cpp