流れ図とCの制御構造

 流れ図は、処理の流れを図を用いて視覚的に表現したもので、フローチャートflowchart)とも呼ばれる。 基本処理を長方形で、条件分岐をひし形で表し、処理の流れを矢印で示す。

構造化プログラミング(structured programming)の制御構造(control structure)とCの文

直線型(逐次) sequence : 文( ;)の並び
選択型(条件分岐) branch : ifswitch
反復型(ループ) loop : whiledofor
プロシージャ procedure : 関数呼出し

プログラム(program)



   
/* 関数定義 */
main()
{
	処理
}
/* 関数定義 */
型 関数名(引数定義)
{
	処理
}
   
/* Hello World と画面に表示する */
main()
{
	printf("Hello World\n");
}
/* 2整数の和を返す */
int add( int x, int y )
{
	return( x + y );
}

処理(process)

/* 処理は文 */
文
/* 最も簡単な文 */
式;
/* 式の後ろにセミコロン */
y = a * x + b;

逐次処理(直線型)(sequential process)

/* 逐次処理 */  
文1
文2
/* 文が一つしか書けない場所に複数の文を書く方法 */
{// ひとつの文にする為に、
	文1 // ブロックの中はインデント(字下げ)する
	文2 // tabを使えば複数行の縦位置を揃えやすい
}
// 中カッコで囲んでブロック(block)にする
/* y = a * x + b を計算する */
y = a * x;
y = y + b;
/* y = a * x + b を計算する */
{
	y = a * x;
	y = y + b;
}

条件分岐(選択型)(conditional branch)

 if文(else無し)



/* 単純if文 */
if(条件)
	文T// 条件が真のとき実行
// インデントして可読性を向上する
/* y = a*x + b を x について解く */
/* a≠0の時だけaで割れる! */
if( a != 0 )
	x = (y - b) / a;
/* ブロックif文 */
if(条件)
{// 処理ブロックT
        文T
        文T
}
/* y = a*x + b を x について解く */
if( a != 0 )
{
	t = y - b;
	x = t / a;
}

※ { } で囲まないと真の処理はブロックにならない!
// インデントしても
if( a != 0 )
	t = y - b;
	x = t / a;
// しなくても同じ流れ
if( a != 0 )
	t = y - b;
x = t / a;
インデントは見易さの為に入れている空白文字にすぎない!
(文法的には空白は有っても無くても構わないってこと)

 if文

/* 単純if文 */
if(条件)
	文T/* 条件が真のとき実行 */
else
	文F/* 条件が偽のとき実行 */
// 各処理文はインデントして可読性を向上する
/* 最大値を求める */
if( a > b )
	max = a;
else
	max = b;
/* ブロックif文 */
if(条件)
{/* 処理ブロックT */
        文T
        文T
}
else
{/* 処理ブロックF */
        文F
        文F
}
/* 最大値と最小値を求める */
if( a > b )
{
	max = a;
	min = b;
}
else
{
	max = b;
	min = a;
}

 if文の入れ子(nesting)

/* 単純if文の入れ子 */
if(条件1)
	文1/* 条件1が真のとき実行 */
else
	if(条件2)
		文2/* 条件1が偽で条件2が真のとき実行 */
	else
		文F/* 条件1も条件2も偽のとき実行 */
// インデントすると構造が手に取るように分かる!
  本来上の様に書くべきだが、
左下の様に書く!
/* 単純if文の入れ子 */
if(条件1)
        文1/* 条件1が真のとき実行 */
else if(条件2)
        文2/* 条件1が偽で条件2が真のとき実行 */
else
        文F/* 条件1も条件2も偽のとき実行 */
// コンパクトで明確な表現になっている

/* b*x + c = 0 を解く */
if( b != 0 )
	x = -c / b;
else if( c != 0)
	printf("解なし\n");
else /* b == 0 && c == 0 */
	printf("不定\n");
/* ブロックif文の入れ子*/
if(条件1)
{/* 処理ブロック1 */
        文1
        文1
}
else if(条件2)
{/* 処理ブロック2 */
        文2
        文2
}
else
{/* 処理ブロックF */
        文F
        文F
}
          
/* a*x*x + b*x + c = 0 を解く */
if( disc < 0 )
{
	printf("実根なし\n");
}
else if( disc == 0)
{
	printf("重根\n");
	x = -b / (2*a);
}
else /* disc > 0 */
{
	printf("2実根\n");
	x1 = (-b + sqrt(disc))/(2*a);
	x2 = (-b - sqrt(disc))/(2*a);
}

 if文の入れ子(その2)

/* 単純if文の入れ子 */
if(条件1)
	if(条件2)
		文12/* 条件1も条件2も真のとき実行 */
	else
		文1/* 条件1が真で条件2が偽のとき実行 */
else
	文F/* 条件1が偽のとき実行 */
// インデントすると構造が手に取るように分かる!

 if文の入れ子(その3)

/* 単純if文の入れ子 */
if(条件1)
	if(条件2)
		文12/* 条件1も条件2も真のとき実行 */
	else
		文1/* 条件1が真で条件2が偽のとき実行 */
// インデントすると構造が手に取るように分かる!

 if文の入れ子(その4)

/* 単純if文の入れ子 */
if(条件1)
{
	if(条件2)
		文12/* 条件1も条件2も真のとき実行 */
}
else
	文F/* 条件1が偽のとき実行 */

/* 中括弧 { } は必要である!
 elseは最も近いelse無しのifに関連付けられるので、
 中括弧 { } が無いと、その3と同じになってしまう */

 switch文




下の図の方が実際の動作に近い!
/* switch文 */
switch(式)
{
case 定数式1:
	処理1
	break;
case 定数式2:
	処理2
	break;
default:
	処理F
}
// 各処理の部分はインデント
/* break;が無いと、その下のcaseや
defaultの処理も続けて行なう */




右のswitch文を実行して確認する
switch( x % 3 )
{
case 0:
	printf("3で割り切れる\n");
	break;
case 1:
	printf("3で割ると1余る\n");
	break;
default:/* 2 */
	printf("3で割ると2余る\n");
}

/* break;の無い例 */
switch( i )
{
case 3:
	printf("*");
case 2:
	printf("*");
case 1:
	printf("*");
default:
	printf("\n");
}

ループ(反復型)(loop、iteration)

 while文

/* while文 */
while(継続条件)
	文R
// 繰り返し処理をインデントして可読性を向上する

/* 99 まで表示する */
while( i < 100 )
	printf("i = %d\n", i++ );
/* 文R中の break; でループの外に出る
continue; で継続条件の評価へ飛んで繰り返す */
/* while文 */
while(継続条件)
{/* 処理ブロックR */
        文R
        文R
}
/* 99 まで表示する */
while( i < 100 )
{
	printf("i = %d\n", i );
	i++;
}
※ { } で囲まないと繰り返しの処理ブロックにならない!
/* 99 まで表示するつもりが、止まらない! */
while( i < 100 )
	printf("i = %d\n", i );
	i++;
インデントは見易さの為に入れている空白文字にすぎない!
(文法的には空白は有っても無くても構わないってこと)
/* 止まらないのは当たり前! */
while( i < 100 )
	printf("i = %d\n", i );
i++;
  • 新jisの流れ図表現
  • 終了条件(継続条件の否定)を書くことになっている
  • 反復構造は一目でよく分かる

 do文

/* do文 */
do
	文R
while(継続条件);
/* do文 */
do
{/* 処理ブロックR */
        文R
        文R
}
while(継続条件);
// 繰り返し処理をインデントして可読性を向上する

/* 文R中の break; でループの外に出る
continue; で継続条件の評価へ飛んで繰り返す */
/* 99 まで表示する */
do
	printf("i = %d\n", i++ );
while( i < 100 );
/* 99 まで表示する */
do
{
	printf("i = %d\n", i );
	i++;
}
while( i < 100 );
  • 新jisの流れ図表現
  • 終了条件(継続条件の否定)を書くことになっている
  • 反復構造は一目でよく分かる

 for文

/* for文 */
for(初期化; 継続条件; 後処理)
        文R

/* for文 */
for(初期化; 継続条件; 後処理)
{/* 処理ブロックR */
        文R
        文R
}

// 繰り返し処理をインデントして可読性を向上する

/* 文R中の break; でループの外に出る
continue; で後処理へ飛んで繰り返す */

「初期化」と「後処理」の部分に、式を ,演算子 で区切って複数置くことができる。

/* 0 から 99 まで表示する */
for( i = 0; i < 100; i++ )
	printf("i = %d\n", i );

(この変数 i ようなものをループカウンタと呼ぶ)

/* 0 から 99 まで表示する */
for( i = 0; i < 100; i++ )
{
	printf("i = ");
	printf("%d\n", i );
}
  • 新jisの流れ図表現
  • 典型的な使い方だと記述できるが...
  • 反復構造は一目でよく分かる

 無限ループ(endless loop、infinite loop)

whileを使った無限ループは、例えば、
while(1)
{/* 無限に繰り返される処理 */

}
      forを使った無限ループは、
for(;;)
{/* 無限に繰り返される処理 */

}

プロシージャ(関数呼び出し)(procedure、function call)

/* 関数呼び出し */
関数名(引数並び);

s = add( i, j ); /* add という関数呼び出し */

printf("sum = %d\n", s ); /* 標準出力関数 */

無条件分岐(unconditional branch)

 goto 文

goto 名札;

名札:

 break文

break;

 continue文

continue;

制御構造の練習問題へ