本当に初心者の人に捧げるコンピューター入門


ソフトウェア プログラム編その7

プログラムの流れを分かりやすく

 前章まではメモリーのある領域に名前を付けるための様々な方法の例を挙げてみました。
 変数や配列などのメモリーに付けた名前とは、言ってしまえば「名詞」です。こう言えば当然「動詞」もあるはずだと思うでしょう?それがこの章の内容です。


制御構造



 プログラムは放っておけば前から後ろに順番に実行されるだけです。それだけではあまり複雑なことはできません。
 前に作った迷宮脱出プログラムも途中で条件分岐をしたり、繰り返しをしたりしていました。
 こういう操作は非常によく行われるので、高級言語ではそれを分かりやすく書く方法が用意されています。
 これを制御構造と呼びます。


条件分岐



 まず最も基本的なのは、ある条件をみてそれが正しければA、正しくなければBという処理をする、という処理です。

 前の偽機械語では、フラグとジャンプ命令を使ってそれを実現していました。しかし初めて見た方はなんだかよく分からなかったのではないでしょうか?
 普通の人が分かりにくいことは、プロでも分かりにくいことです。そこで高級言語では例えば以下のように書けるようになっています。

 if X=True then A else B;

これをif文といってその意味は

もしXが真であればAという処理を行い、そうでなければBという処理を行え

です。そのまんまですね。

 もしelseのあとのBという処理が何もない場合は、

 if X=True then A;

とだけ書いても構いません。

 ちなみにAやBでやる処理が一つの文で書けるようなものならいいのですが、結構複雑なことをさせたいこともあります。
 例えばAでやりたいことが

 R := X+20; 
 S := R+Y+30; 
 if S>100 then R := -R; 

といった感じで何行にもわたることはよくあります。
 ところがこれを上記のIF文に直接入れると・・・

if X=True then R := X+20;S := R+Y+30;if S>100 then R := -R; else B;

となってなんだかよく分かりません。

 そこでPASCALではこういうたくさんの文をひとまとめにして一個として扱いたいときには、begin と end で囲みます。そうやって書くと上の文は

if X=True then begin R := X+20;S := R+Y+30;if S>100 then R := -R end else B;

となります。

    ここの内容からははずれる話ですが、上のように横にだらっと書くと大変読みにくいです。そこでPASCALでは適当に改行を入れていいことになっています。

{改行を入れた例1} 
 if X=True then  
   begin  
   R := X+20; 
   S := R+Y+30; 
   if S>100 then R := -R 
   end
 else B;

{改行を入れた例2}
 if X=True then begin
   R := X+20;
   S := R+Y+30;
   if S>100 then R := -R 
 end else B;

上記の2例は全く内容は同じです。
(どっちの例が優れているかという点については、宗教問題に発展するのであまり深入りしない方がいいでしょう)

一度にたくさん条件分岐



 さて、条件分岐に関しては、if文だけあれば実はいいのですが、実際上いろいろなたくさんの条件の中から一つを選ぶことができた方が便利です。そういう場合には

 case 「式」 of r1:A; r2:B; ... else XX end;

という文(これをcase文という)を使います。

 これは「式」に適当な変数や計算式を書いておいて、その結果がr1だったらA、r2だったらB、どれでもなかったらelseのあとのXXを実行せよという命令です。

 このcase文というのは、やろうと思ったらif文の組み合わせでもできるので、言語によっては無いこともあります。


ループ処理



 プログラムにはまた「同じようなことを繰り返す」という処理も良く出てきます。迷宮脱出プログラムでも、出口に達するまで繰り返せ!とやっていました。
 こういう処理も専用の書き方があって、

 while X=True do A;

と書き、while文といいます。これはXが真の間はAをやっていろ!という意味です。
 また

 repeat A until X=True; {XがTrueになるまでAをやっていろ!}

というrepeat文とか、

 for i:=1 to 100 do A;  {Aを100回繰り返せ!}

というfor文というのもあります。

 三つも種類があるのはそれなりに使い道があるからですが、細かいことは省略します。プログラムの入門書を見るとたいていまずこれの使い方から入っているのが普通です。


gotoとラベル



 gotoとは、前の機械語の説明にも出てきたジャンプの機能と全く同じ物と考えてくださって結構です。
 機械語の場合は

 JMP 2000

とか言う感じで飛び先のアドレスを指定しました。
 同じような感じでPASCALには

 goto ジャンプ先;

という書き方があります。

 しかし高級言語ではアドレスを直接扱わないのが原則です。しかしこういうジャンプをしたい以上、アドレスが無いと困ります。

 それを回避するためにはまず「第何行目の処理にジャンプする」という方法を思いつくと思います。
 でも単純にこうすると、途中に行の追加や削除があったら、ジャンプ文の飛び先が全部変わってしまいます。

 そこでジャンプしたい行に印を付けておきます。この印をラベルといいます。
 そこで実際には

 BILL:     {この行にBILLというマーク(ラベル)をつけておく} 
 何かのプログラム
 .......
 goto BILL;  {この行に来たらBILL:と書いてある行に飛ぶ} 

というような書き方をします。


それから?



 というわけで、制御構造は終わりです。
 ええ?これだけ?と思う人がいるかも知れません。でも実際、これだけあれば十分なんです。それどころか上記の3つある必要さえないんです。

 例えば、条件分岐とgotoだけあればループは必要ありません。

 while X=True do Aという処理; 

 BILL: 
 if X=True then begin 
   Aという処理; 
   goto BILL; 
 end; 

 上の二つはよく見ると全く同じ処理ですね。

 だったら二つでいいじゃないか!と思います。どうしてわざわざループ文なんていう物を作ったのでしょう?

 まあ、上の方が楽に書けそうだから、というのは強力な理由になりますが、それだけではないのです。
 このあたりの事情は構造化プログラミング言語理論とか言うような名前で、詳しく話し始めたらきりがないので詳細は割愛しますが、滅茶苦茶簡単に説明すれば大体以下のような感じでしょうか。

 実は大昔のプログラミング言語では、if文を書くにもgoto文が必須でした。すなわち、

 if X=True then A else B;

ということができなくて

 if X=True then goto ラベル;

という書き方をしていました(昔のBASICを習ったことのある人なら思い出しますね?)別な言い方をすれば、beginendを使って複数の行をひとまとめに扱うことができなかったと言ってもいいです。

 ところがこのgoto文のジャンプ先というのは、その気になればプログラム中のどこでも指定できます。それはある意味便利なのですが、濫用するととんでもないことになります。例えばプログラムが

 A: 処理α
 goto B;
 C: 処理β
 goto D;   ←こういうのをスパゲッティプログラムという 
 B: 処理γ
 goto C:
 D:

なんて書かれていたとします。
 見て一瞬でどういう順序でプログラムが実行されるか分かりますか?もしもっとgotoが多くて、大きなプログラムで何ページにもわたるような物だったら?
(暇な人はちょっとこの例を・・・)

 というわけでgotoをいい加減に使っていると確実に、そのプログラムを書いた本人であっても、三日後には何が書いてあるのか分からなくなります

 だったら、goto文を勝手に使えないように制限してしまえば、こういう問題をなくせると思いませんか?

 実際プログラムを良く研究してみると、gotoがどうしてもいるのは、条件分岐とループの所だけで、それ以外のところのgotoはプログラムの順序を入れ替えるだけでなくすことができます。上の例はよく見れば

 処理α 
 処理γ 
 処理β 

というのと全く同じです。

 とまあ、こんな感じでgotoを使わずに条件分岐とループに特別な書き方を導入すれば、プログラム全体が見やすくなるわけです。
(プログラムを書いた本人ならば、半年ぐらいは覚えていられるようになります)


前へ 目次へ 次へ