CONTENTS / BACK-PAGE / NEXT-PAGE

4 処理の制御

 3章でプログラムは、上から下へ順に実行されることを学んだ。本章では、ある条件によてプログラムの実行の流れを変更させたり、同じ所を何度も繰り返し実行させたりするプログラムの制御構造について学ぶ。

4.1 条件文 −2方向分岐 if_else文−

 条件判定を行なって実行する文を選択することができる。それがif_else文である。if_else文は、つぎのような形式をしている。各形式の下に流れ図を示す。

 ここで(式)は(式!=0)と書いても同じ意味である。これは、式の評価値が真(すなわち 式≠0 )の時文1を実行し、それ以外の時に文2の実行を実行することになる。elseなしの場合は、式の評価値が真の時のみ文1を実行し、それ以外の時には何もしない。例4−1を考える。


例4−1

 入力した数値が奇数であるか偶数であるかを判定し、奇数または偶数と出力するプログラムをつくる。

考え方:

 数値を2で割り、余りが1の時には奇数、余りが0の時には偶数と出力する。


プログラム4−1

/*  1 */  /* Program 4-1  */
/*  2 */  /*  奇数,偶数 判定  */
/*  3 */  #include <stdio.h>
/*  4 */  main()
/*  5 */  {
/*  6 */      int a;
/*  7 */ 
/*  8 */      scanf("%d", &a);
/*  9 */      if ( a%2 == 1 )
/* 10 */          printf("%d ... odd\n", a);
/* 11 */      else
/* 12 */          printf("%d ... even\n", a);
/* 13 */  }


実行例

11 11 ... odd 20 20 ... even

***解説***

8:数値を整数として入力する。
9:if文である。条件式として a%2==1 とする。これは、aを2で割った余りが1と等しければ真(0以外の数値)、等しくなければ偽(0)を値としてもつ。つまり式の値は、0または1である。
10:条件式の値が0以外の時に、文1つまり10:の文が実行され奇数と出力される。文の終わりに、;をつけることを忘れずに。
11:if_else文のelseである。elseは1行に書くこと。
12:ifの条件式の値が0の時に、12:の文が実行される。

 ここで、if(a%2==1)をif(a%2)と変更しても同じ結果が得られる。

 実行例からもわかるように、a%2が1の時には、..,8,9,10,13と実行され、a%2が0の時には、..,8,9,11,12,13と実行される。


例4−2

 3つの数値を読み込んで、最大値を出力するプログラムを作る。

考え方:

 3つの数値をそれぞれa,b,cとし最大値をmaxとする。

  1. a,b,cに数値を入力する。
  2. aとbを比較し、数値の大きい方をmaxに代入する。
  3. maxとcと比較し、cの数値が大きければ、cの値をmaxに代入する。
  4. この時点でmaxの値は、a,b,cの最大値が代入されている。

    maxを出力する。

    流れ図


    プログラム4−2

    /*  1 */  /*  Program 4-2  */
    /*  2 */  /*  3つの数の最大値を求める.  */
    /*  3 */  #include <stdio.h>
    /*  4 */  main()
    /*  5 */  {
    /*  6 */      int a, b, c, max;
    /*  7 */ 
    /*  8 */      scanf("%d %d %d", &a, &b, &c);
    /*  9 */      if (a > b)
    /* 10 */          max = a;
    /* 11 */      else
    /* 12 */          max = b;
    /* 13 */      if (c > max)
    /* 14 */          max = c;
    /* 15 */      printf("%d %d %d max = %d\n", a, b, c, max);
    /* 16 */  }
    
    
    

    実行例

    4 3 2 4 3 2 max = 4 6 9 1 6 9 1 max = 9

    ***解説***

    8:3つの整数を変数a,b,cに入力する。
    9−12:aとbの値を比較し、aの値がbの値より大きい時maxにaの値を代入し、それ以外の時maxにbの値を代入する。ここで、9: の if と 11: の else を同じだけ字下げして書くことを薦める。(下記の注意を参照のこと。)
    13:cとmaxの値を比較し、cの値がmaxの値より大きい時maxにcの値を代入し、それ以外の時はなにもしない。
    15:a,b,cの値を出力したあとに、最大値maxの値を出力する。

    ***注意***

    	if ( a>b )
    	     if( b>c )   x = c;
    	else   x = b;
    
    をどのように解釈したらよいのだろうか?

     C言語の場合、elseは一番近いifに対応する。つまりこの場合、a>bかつb>cのときx=cが実行され、a>bかつb<=cのときx=bが実行される。a<=bのときにはなにも実行されない。よって、上記プログラムは

    のように解釈されるため

    	if ( a>b )
    	       if( b>c )   x = c;
    	       else   x = b;
    
    のように対応する if と else を同じだけ字下げして書換えたほうがよい。

     このように、人間の意向を明確にするために、段付け(字下げ)を行いプログラムを見やすくする。この場合、elseを1つめのifにあわせて書くと、見かけ上人間が誤った解釈をしやすく、虫(バグ)が発見しづらくなるので注意が必要である。正確に段付けを行なうことは、プログラムを見やすくするばかりでなく誤りを防ぐにも効果的である。

     a>bかつb>cのときにx=cの実行を、a>bかつb<=cのときなにも実行しない、a<=bのときx=b実行するようにするには、ブロック{ }を用いる。{ と } で複数の文を囲んで一つの文と解釈することができる。つまり、

    のような制御の流れをつくるには、プログラムを次のように変更すればよい。

    	if ( a>b ) {
    	     if( b>c )   x = c;
    	}
    	else   x = b;
    
    この場合、 if ( a>b ) 文1; else x = b; で、文1の中身が if ( b>c ) x = c; である。

      また、

    	if ( a>b ) {
    	        文a;
    	        文b;
    	        文c;
    	        文d;
    	   }
    	   else {
    	        文v;
    	        文w;
    	        文x;
    	        文y;
    	        文z;
    	   }
    
    のようなプログラムの場合、a>bのとき文a〜文dを実行し、a<=bのとき文v〜文zを実行することになる。{ と } で囲むことによって複数の文を一つの文とみなすことができる。よって、if_elseの形式で文1、文2に対応する部分は、{ }でブロックを作ってやれば、複数文を1文と解釈してやることが可能となる。


 ここで、よく使われる算術演算子,比較演算子,論理演算子についてまとめてみる。

 算術演算子は、数値の+,−,×,÷などを行なうためのものである。演算結果は数値である。以下の表のようにまとめることができる。

優先順位演算子種類解説
単項演算子 +x
単項演算子 −x
2項演算子 x × y
÷ 2項演算子 x ÷ y
2項演算子 (x÷y)の余り
2項演算子 x + y
2項演算子 x − y
 ここで優先順位とは、いくつもの演算子が混ざった式の計算を行なうときの演算の行なう順番で、順位が小さいほど先に計算をする。同じ優先順位の演算子があるときには、左から順に行なうものとする。ただし、括弧があるときには一番内側の括弧の中から先に計算する。例えば、

a÷b+((c%d)−(e+f))*−d
の計算は、以下の順序で行なわれる。

  1.  a÷b
  2.  (c%d)
  3.  (e+f)
  4.  2の結果−3の結果
  5.  −d
  6.  4の結果×5の結果
  7.  1の結果+6の結果
 比較演算子は、if文の条件式内などでよく用いられる。評価(演算)結果は、真(0以外)または偽(0)である。以下の表にまとめる。

優先順位演算子利用例解説
a<b aの値がbの値未満
<= a<=b aの値がbの値以下
a>b aの値がbの値より大
>= a>=b aの値がbの値以上
== a==b aとbの値が等しい
!= a!=b aとbの値が等しくない
 ここで、優先順位が小さいほうが、先に計算される。

 論理演算子は&&と||で、上記算術演算子,比較演算子を使った式を組み合わせることによく用いられる。例えば、a>bかつb>c a>b && b>c a>bまたはb<c a>b || b<c のように書くことができる。評価結果は、真(0以外)または偽(0)である。

優先順位演算子利用例解説
&&a && baかつb
||a || baまたはb
 上記3種類の演算子の間にも優先度があり以下の通りである。

優先順位演算子
算術演算子
比較演算子
論理演算子
 つまり、算術演算のほうが論理演算よりも先に評価される。例えば、 a+b>c && x<=y は 以下の順序で評価される。

	1 a+b
	2 1の結果>c
	3 x<=y
	4 2の結果 && 3の結果
if文の式では、このような各種の演算子を組み合わせた式を書くこともで きる。


4.2 条件文 −多方向分岐 switch_case文−

 2方向への分岐は、if文を使って実現できた。ここでは、多方向への分岐について考えてみる。当然、多方向分岐はif文を組み合わせて実現可能であるが、例えば10方向への分岐の場合、9個のif文を書かなければならない。そこで、多方向分岐を実現するswitch_case文がある。switch_case文の形式は、下記のようである。

	switch (式) {
	   case 定数式:文1;
	   case 定数式:文2;
	   case 定数式:文3;
	     :
	     :
	   default: 文n;
	 }

例4−3

1から3の数値を入力すると、対応する英単語を出力するプログラムを作る。

考え方:

  1. 数値を入力する
  2. 入力した数値が1と等しければoneを出力、2と等しければtwoを出力、...といった具合いに一つづつ比べる。

流れ図

 このようなケースには、switch−case文が役に立つ。


プログラム4−3−1

/*  1 */  /*  Program 4-3-1  */
/*  2 */  /*  数値を英単語に直す  Ver. 1  */
/*  3 */  #include <stdio.h>
/*  4 */  main()
/*  5 */  {
/*  6 */      int x;
/*  7 */ 
/*  8 */      scanf("%d", &x);
/*  9 */      switch ( x ) {
/* 10 */          case 1: printf("One\n"); break;
/* 11 */          case 2: printf("Two\n"); break;
/* 12 */          case 3: printf("Three\n"); break;
/* 13 */          default: printf("otherwise\n"); break;
/* 14 */      }
/* 15 */  }


実行例

3 Three 2 Two 4     ←何も表示されない

解説

8:数値の入力。xに整数として読み込む。
9〜14:switch−case文である。xの値によって実行文が変わる。この場合、x=1のとき10:を、x=2のとき11:を、x=3のとき12:を実行する。それぞれ printf で英単語を出力したのち break 文によってswitch−cace文をぬける。つまり14:へ制御が移る(実行がとぶ)。 もし、10:で break 文をなくすと、x=1のときには One と Two が出力される。これは break 文がないために制御が次の文(11:)に移ったため、 Two も出力されることになる。
13: default: は、caseで該当するものがないときに実行したい文を記述しておける。この場合、x=1,2,3のいずれでもないときに otherwise と出力される。


練習問題

 break 文を工夫して、1から5までの数値の入力に対し、入力した数値か ら5までの英単語をすべて出力するプログラムをつくる。

	例 入力:2  出力:two three four five
	  入力:4  出力:four file
	  入力:7  出力:otherwise
 switch−case文は、if文の拡張であることを前にも説明した が、以下では例4−3をif文を使って実現してみよう。


流れ図−2


プログラム4−3−2

/*  1 */  /*  Program 4-3-2  */
/*  2 */  /*  数値を英単語に直す  Ver.2  */
/*  3 */  #include <stdio.h>
/*  4 */  main()
/*  5 */  {
/*  6 */      int x;
/*  7 */ 
/*  8 */      scanf("%d", &x);
/*  9 */      if (x == 1)
/* 10 */          printf("One\n");
/* 11 */      else if (x == 2)
/* 12 */          printf("Two\n");
/* 13 */      else if (x == 3)
/* 14 */          printf("Three\n");
/* 15 */      else
/* 16 */          printf("Otherwise\n");
/* 17 */  }


実行例

3 Three 2 Two 4 Otherwise

***解説***

9−16:プログラム4−3−1の 9:-14: で行なっていることを if-else 文を組み合わせて実現している。この例のプログラムは if 文が3重になっていて、else がどのif と対応しているのかがわかりづらいのが、難点である。

流れ図−3


プログラム4−3−3

/*  1 */  /*  Program 4-3-3  */
/*  2 */  /*  数値を英単語に直す  Ver. 3  */
/*  3 */  #include <stdio.h>
/*  4 */  main()
/*  5 */  {
/*  6 */      int x;
/*  7 */ 
/*  8 */      scanf("%d", &x);
/*  9 */      if (x == 1)
/* 10 */          printf("One\n");
/* 11 */      if (x == 2)
/* 12 */          printf("Two\n");
/* 13 */      if (x == 3)
/* 14 */          printf("Three\n");
/* 15 */  }


実行例

3 Three 2 Two 4     ←何も表示されない

***解説***

9−14:この場合、3つの if 文を用いて実行している。break のような文はなく、すべての if 文で判定され、x の値が該当する時のみ英文が出力される。このように if 文のみを使って実現した場合、x=1,2,3 のでれでもない時には、otherwise を出力することが難しくなる。14: と 15: の間に
	 if (!( x==1 || x==2 || x=3 ))
	    printf("otherwise\n");
を挿入すれば実現できるが、あまりエレガントではない。


 上記switch−case文とif文を用いたプログラム例を比較してもらいたい。この場合はプログラムの行数に違いはないが、流れ図を見ると同じif文でも違った構造になっている。つまり、問題が与えられ考え方が決ってもそれを実現する方法が、いろいろ考えられる。そこで、問題に適した分かりやすく見やすい方法を採用すべきである。例4−3の場合は、C言語にswitch−case文というものがあるのでこれを使うのが最良と考えられる。これが人間の思考と最も合致すると思われるからである。

 ここで、もう少し実際的な例を考えよう。

例4−4 ax^2+bx+c=0 を解の公式を用いて解くプログラムをつくる。

解の公式: D=b^2-4ac としたとき

      D=0 のとき x = -b/2a
      D>0 のとき x = (-b+ D )/2a , (-b- D )/2a
      D<0 のとき x = (-b+ (-D) i)/2a , (-b- (-D) i)/2a

     ただし、a,b≠0 とする。

流れ図

 このような場合は、このままではswitch−case文を使うことが できない。Dの値が実数になってしまうからである。よってif文を使うか 、工夫してswitch−case文を使う。


/*  1 */  /*  Program 4-4-1  */
/*  2 */  /*  2次方程式を解く  Ver.1  */
/*  3 */  #include <stdio.h>
/*  4 */  #include <math.h>
/*  5 */ 
/*  6 */  main()
/*  7 */  {
/*  8 */      float a, b, c, d, x1, x2;
/*  9 */ 
/* 10 */      scanf("%f %f %f", &a, &b, &c);
/* 11 */ 
/* 12 */      d = b * b - 4 * a * c;
/* 13 */      if ( d > 0.0 )
/* 14 */      {
/* 15 */          x1 = ( -b + sqrt(d)) / ( 2 * a);
/* 16 */          x2 = ( -b - sqrt(d)) / ( 2 * a);
/* 17 */          printf("%f, %f\n", x1, x2);
/* 18 */      }
/* 19 */      else if ( d < 0.0 )
/* 20 */      {
/* 21 */          x1 = -b / ( 2 * a );
/* 22 */          x2 = sqrt(-d) / ( 2 * a );
/* 23 */          printf("%f+%fi, %f-%fi\n", x1, x2, x1, x2);
/* 24 */      }
/* 25 */      else
/* 26 */      {
/* 27 */          x1 = -b / ( 2 * a );
/* 28 */          printf("%f\n", x1);
/* 29 */      }
/* 30 */  }

実行例

1 2 1 -1.000000 3 2 1 -0.333333+0.471405i, -0.333333+0.471405i

***解説***

4:計算の中で (ルート:2乗根) の計算をするために、数学計算用の関数ライブラリを利用する宣言をする。
10:方程式のa,b,cを実数型で入力する。
12:判別式 D の計算をする。
13−18:D>0の時の計算を行なう。判別式の値が正であるので、2つの異なる解を持つため、それぞれを x1, x2 として公式にあてはめ計算している。ここで、sqrt は 4: で宣言した math.h ライブラリ内の関数で2乗根をもとめるための関数である。sqrt を用いるために 4: の宣言が必要である。
19−24:D<0のときは異なる虚数解を持つため、実部を x1, 虚部を X2 として計算し、出力のときに虚数部の後に "i" を出力するようにしている。
25−29:D=0のときは、重解をもつためそれを x1 として、計算している。


もうひとつのプログラム例を示そう。これは、故意にswitch−case文を用いた例である。


/*  1 */  /*  Program 4-4-2  */
/*  2 */  /*  2次方程式を解く  Ver.2  */
/*  3 */  #include <stdio.h>
/*  4 */  #include <math.h>
/*  5 */ 
/*  6 */  main()
/*  7 */  {
/*  8 */      float a, b, c, d, x1, x2;
/*  9 */      int sw;
/* 10 */ 
/* 11 */      scanf("%f %f %f", &a, &b, &c);
/* 12 */ 
/* 13 */      d = b * b - 4 * a * c;
/* 14 */      if ( d > 0.0 )
/* 15 */          sw = 1;
/* 16 */      else if ( d < 0.0 )
/* 17 */          sw = 2;
/* 18 */      else
/* 19 */          sw = 3;
/* 20 */ 
/* 21 */      switch (sw) {
/* 22 */          case 1:
/* 23 */              x1 = ( -b + sqrt(d)) / ( 2 * a);
/* 24 */              x2 = ( -b - sqrt(d)) / ( 2 * a);
/* 25 */              printf("%f, %f\n", x1, x2);
/* 26 */              break;
/* 27 */          case 2:
/* 28 */              x1 = -b / ( 2 * a );
/* 29 */              x2 = sqrt(-d) / ( 2 * a);
/* 30 */              printf("%f+%fi, %f-%fi\n", x1, x2, x1, x2);
/* 31 */              break;
/* 32 */          case 3:
/* 33 */              x1 = -b / ( 2 * a);
/* 34 */              printf("%f\n", x1);
/* 35 */              break;
/* 36 */      }
/* 37 */  }

実行例

4 32 1 -0.031373, -7.968627 1 -2 1 1.000000

***解説***

 大筋の考え方はプログラム4−4−1と同じである。ここではswich−case文を用いるために、sw という変数を導入し 14:-19: の if 文で D の値によって sw に 1,2,3 を代入している。こうすることによって 21: からのswitch文を使うことができるようになる。caseの後に書く定数は、数値の場合整数のみであり実数は扱えないからである。


4.3 繰り返し処理

 同じような処理を繰り返し何回も行わせることは、プログラムにとって大変得意とすることである。次の例4−5を考えてみよう。繰り返しのことをループ呼ぶこともあるので、覚えておいて下さい。


例4−5 1から与えられた整数までの総和を求めるプログラムを作る。

考え方:

 与えられた整数をnとすると、総和は次のような式で書ける。

souwa = 1 + 2 + 3 + ・・・・ + n
 これをアルゴリズムで考える。

	1 souwa を0に初期化する
	2 i を1に初期化する
	3 souwa に i の値を加える
	4 i の値に1を加える
	5 i の値が n より小さい時はステップ3へ、それ以外の時はステップ6へ
	6 souwa を出力

流れ図

 繰り返しを実現するために、C言語では3種類の繰り返し文を用意してい る。while,do−while,forの3つである。以下、これらの 一般形式について解説し、例4−5をそれぞれの文でプログラムしてみる。


(1) while文

 while文は条件判定が文頭にあり、繰り返しの本体がそれに続く。一般形式は次のようである。

	条件式の初期化;
	while( 繰り返しの条件式 ){
	      文1;
	      :
	      :
	      文n;  
	}

 繰り返しの条件式の値が真の間は、文を繰り返し実行する。流れ図からも見られるように繰り返しの実行前に、条件式を評価している点がwhile文の特徴である。条件式の値によっては、文1−文nが1度も実行されないこともある。また、通常while文のまえに、条件式の初期化文が置かれている。{文1−文n}が1文の時には、while( )のあとに{ }を省いて文を書いてもよい。

 それでは、while文を使って例4−5をプログラムしてみよう。


プログラム4−5−1 whileを使った例

/*  1 */  /*  Program 4-5-1                      */
/*  2 */  /*  1からnまでの合計を求める  Ver 1  */
/*  3 */  #include <stdio.h>
/*  4 */  main()
/*  5 */  {
/*  6 */      int souwa,i, n;
/*  7 */ 
/*  8 */      scanf("%d", &n);
/*  9 */      souwa = 0;
/* 10 */      i = 1;
/* 11 */      while(i <= n)
/* 12 */      {
/* 13 */          souwa = souwa + i;
/* 14 */          i = i + 1;
/* 15 */      }
/* 16 */      printf("%d\n", souwa);
/* 17 */  }

実行例

10 55

***解説***

9:総和を求めるための変数 souwa を0に初期化する。これは、 13: で souwa = souwa + i として利用するためである。
10:while文の条件の初期化文である。
11:while文の始まりで、12:から15:が繰り返しの本体である。繰り返しの条件として i <= n を満たしているあいだ繰り返される。
13:総和にiの値が繰り返し加えられるため、最終的には1からiの総和が求まる。


(2) do−while文

 do−while文は、条件判定が繰り返し文の後ろに付く点でwhile文とは、異なる。一般形式と制御の流れは以下のようである。

	do{
	      文1;
	      :
	      :
	      文n;
	}while( 繰り返しの条件式 )

 文1−文nが実行された後に繰り返しの条件式を評価し、その値が真なら ば文1−文nが再び実行され、式の値が偽ならば繰り返しが終了する。つま り、条件式の値が真の間は、文1−文nが繰り返し実行される。またdo_ while文では、必ず1回は文1−文nが実行されることに注意して欲し い。

 while文の時にあった条件式の初期化が、do_while文に入る 前に必ずしも必要ではない。それは、文1−文nでなんらかの条件判定式に かかわる演算を行なう可能性があるからである。逆に、while文は、先 頭に条件判定があるために、条件式の初期化が前もって必要なのである。

 プログラム4−5−2にdo_whileの例を示す。


プログラム4−5−2 do_whileを使った例

/*  1 */  /*  Program 4-5-2                      */
/*  2 */  /*  1からnまでの合計を求める  Ver 2  */
/*  3 */  #include <stdio.h>
/*  4 */  main()
/*  5 */  {
/*  6 */      int souwa,i, n;
/*  7 */ 
/*  8 */      scanf("%d", &n);
/*  9 */      souwa = 0;
/* 10 */      i = 1;
/* 11 */      do{
/* 12 */          souwa = souwa + i;
/* 13 */          i = i + 1;
/* 14 */      }while( i <= n);
/* 15 */      printf("%d\n", souwa);
/* 16 */  }

実行例

5 15

***解説***

11:do_whileの始まりである。繰り返しの本体が12:−13:である。
14:繰り返しの終了条件で、 i <= n のあいだ繰り返される。


(3) for文

 for文は、while文の形式を1つの文に納めたものである。つまり、while文

	 式1;
	 while ( 式2 ){
	    文;
	    式3;
	 }
は,for文で

	 for( 式1; 式2; 式3 ){
	    文;
	 }
のように書ける。ここでfor文の文は複文( 複数の文を { } を使って表現したもの )でもよい。

 制御の流れはwhile文と同じである。for文は、まず式1で条件の初期化をする。式2で繰り返しの条件判定を行い、その値が真の時に文を実行し、偽の時にfor文を終わる。文が実行された後に式3を実行し、その後 式2を評価する。これを式2の値が真の間繰り返し行なわれる。つまり、式1を最初に1度実行し、式2の条件が真の間文と式3を実行することになる。式1−式3はそれぞれ、1つの式でなくてもよい。複数の式を書きたいときには、,で区切って複数の式を並べてもよい。

 プログラム4−5−3にfor文を使ったプログラムを示す。


プログラム4−5−3  for文を使った例

/*  1 */  /*  Program 4-5-3                      */
/*  2 */  /*  1からnまでの合計を求める  Ver 3  */
/*  3 */  #include <stdio.h>
/*  4 */  main()
/*  5 */  {
/*  6 */      int souwa,i, n;
/*  7 */ 
/*  8 */      scanf("%d", &n);
/*  9 */      souwa = 0;
/* 10 */      for (i = 1; i <= n; i = i + 1)
/* 11 */          souwa = souwa + i;
/* 12 */      printf("%d\n", souwa);
/* 13 */  }

実行例

20 210

***解説***

10:for文のヘッダである。通常for文は、式1(i=1)が繰り返し文の条件
11:繰り返しの本体である。


 上記の例からもわかるように、それぞれ特徴があり用途によって使い分けられる。例えば、条件判定が繰り返し文の後ろに置きたい時はdo_while文を使うし、条件判定が前の時であらかじめ繰り返しの回数がはっきり判っている時にはfor文を使う。また、for文を利用した場合プログラムの長さが短くなる。

 次の例を考えよう。


例4−6 整数値を読み込んでその大きさの直角二等辺三角形(ここでは縦 ,横に同じ個数の '*' が並ぶものを二等辺とする)をつくる。

入力:5
出力:*****
   ****
   ***
   **
   *

考え方:

初めの行にn個の*を出力し改行する。
次の行にn−1個の*を出力し改行する。
次の行にn−2個の*を出力し改行する。
  :
  :
最後に1個の*を出力し改行する。
 このように考えると、*の出力の個数をn個から1個まで(n行)出力す るような、繰り返し文を書けばよいことに気付く。

アルゴリズム

1  n の入力
2  i を n , n-1, n-2, ..., 1 まで3,4を繰り返す(出力の行数のカウント)
 3  *を i 個出力する
 4  改行する
5  終わり
 ここで3は、

 3.1  j を 1, 2, ... ,i まで 3.2を繰り返す
  3.2  *を1つ出力する
のように詳しく書くことができる。

 よって、繰り返しが2重になっていることがわかるであろう。

 以下3種類のプログラムをあげ、比較してみよう。


プログラム4−6−1 while版

/*  1 */  /*  Program 4-6-1                      */
/*  2 */  /*  直角二等辺三角形を表示する  Ver 1  */
/*  3 */  #include <stdio.h>
/*  4 */  main()
/*  5 */  {
/*  6 */      int i, j, n;
/*  7 */ 
/*  8 */      scanf("%d", &n);
/*  9 */      i = n;
/* 10 */      while(i > 0)
/* 11 */      {
/* 12 */          j = 1;
/* 13 */          while(j <= i)
/* 14 */          {
/* 15 */              printf("*");
/* 16 */              j = j + 1;
/* 17 */          }
/* 18 */          printf("\n");
/* 19 */          i = i - 1;
/* 20 */      }
/* 21 */  }


実行例

5 ***** **** *** ** *

プログラム4−6−2 do_while版

/*  1 */  /*  Program 4-6-2  */
/*  2 */  /*  直角二等辺三角形を表示する  Ver 2  */
/*  3 */  #include <stdio.h>
/*  4 */  main()
/*  5 */  {
/*  6 */      int i, j, n;
/*  7 */ 
/*  8 */      scanf("%d", &n);
/*  9 */      i = n;
/* 10 */      do{
/* 11 */          j = 1;
/* 12 */          do{
/* 13 */              printf("*");
/* 14 */              j = j + 1;
/* 15 */          }while(j <= i);
/* 16 */          printf("\n");
/* 17 */          i = i - 1;
/* 18 */      }while(i > 0);
/* 19 */  }

実行例

4 **** *** ** *

プログラム4−6−3 for版

/*  1 */  /*  Program 4-6-3                      */
/*  2 */  /*  直角二等辺三角形を表示する  Ver 3  */
/*  3 */  #include <stdio.h>
/*  4 */  main()
/*  5 */  {
/*  6 */      int i, j, n;
/*  7 */ 
/*  8 */      scanf("%d", &n);
/*  9 */      for(i = n; i > 0; i = i -1)
/* 10 */      {
/* 11 */          for(j = 1; j <= i; j = j + 1)
/* 12 */              printf("*");
/* 13 */          printf("\n");
/* 14 */      }
/* 15 */  }


実行例

8 ******** ******* ****** ***** **** *** ** *

***解説***

 上記3種類の繰り返し文で、例題4−6を記述してみた。この例題の場合、for文で記述するのが自然であろう。プログラムが短く、意図したことが明確に表現できているからである。for文が必ずしも良いのではなく、問題によってはwhile文やdo−while文が適しているものもあるので、注意してほしい。


演習問題

例4−6の出力を次のように変更せよ。

	入力:4
	出力:        *
	          * *
	         *   * 
	        *******

***注意***

本解説のなかで

		while(i > 0)
		{
		    j = 1;
		     :
		}
のように while(  ) のあとに改行して { をつけるスタイルと、参考書な どによっては

		while(i > 0) {
		    j = 1;
		     :
		}
のように while(  ) のすぐあとに { をつけるスタイルがある。カーニハ ン著の「プログラミング言語C」や各種の参考文献では後者のスタイルを採 用しているものが多いが、ここでは前者のスタイルに統一することとする。 とちらが良い,悪いというこはないのだが、著者の考えでは{ と }の位 置が対応づいているため分かりやすいのではないかと考えている。


CONTENTS / BACK-PAGE / NEXT-PAGE