7

この章では,Cプログラミング言語における次の種類の文について説明します。 この章で示す文以外の文は,関数本体に現れる順序で実行されます。

7.1 ラベル付き文

ラベルは,goto文または switch文の行き先として, プログラム内のある位置にフラグを立てる際に使用する識別子です。 その構文は以下のとおりです。


   識別子 : 

      case 定数式 : 文
      default : 文

ラベルのスコープはそのラベルを含んでいる関数本体です。変数には, 関数内のラベルと同じ名前をつけることができます。これは,ラベルと変数の名前空間が異なるからです。 第2.15 節を参照してください。

C言語のラベル付き文には,次の3種類があります。

case文と default文は, switch文の中にのみ指定します。第7.5.2項を参照してください。

7.2 複文

複文,すなわちブロックは一連の文を単一の文として 扱うことができます。 複文は左中括弧で開始し, 宣言と文を任意の順で含み,右中括弧で終了します。次にその例を示します。

     {
        int a;
        a = 1;
        int b;
        b = 2;
     }


注意
コモンC,VAX C,Strict ANSI89モードでは, 複文の中で宣言と文を任意の順序にすることはできません。 これらのモードでは,宣言を最初に指定し,その後に文を続けなければなりません。

ブロック宣言は各ブロック内でのみ有効であり,そのブロック内では外側のスコープで宣言されている同じ名前の他の宣言に優先します。

制御フローがブロックに入るか,または goto文がそのブロックの始めのラベルに制御を渡すと, そのブロックは正常に開始されます。 ブロックが正常に開始されるたびに,auto または register変数に対して記憶域が割り当てられます。 これに対して goto文が制御をブロック内のラベルに渡した場合, またはブロックが switch 文の本体である場合にはこの記憶域の割当ては行われません。記憶域クラスについての詳細は, 第2.10節を参照してください。

関数定義は複文を含んでいます。関数定義において,仮引数宣言に続く複文を関数本体と呼びます。

7.3 式文

式の後にセミコロンを付けることによって,有効な式を文として使用することができます。 次にその例を示します。

     i++;

この文は,i 変数の値を増分します。 i++ はC言語の複雑な文にも現れるC言語の有効な式です。C 言語の式についての詳細は,第6章を参照してください。

7.4 空文

空文は,C言語の文法により文を必要とする場合に空演算を行う際に使用されますが, プログラム中で特に作業を行う必要はありません。空文はセミコロンで構成されます。

;



空文は ifwhiledo,および for文を使用する際に役に立ちます。この文は主に, すべてのループ処理がループの判定部分で実行される場合にループ演算において使用されます。 たとえば,次の文では配列中の値が0の最初の要素を見つけます。

     for (i=0; array[i] != 0; i++)
        ;

この例の for文はその副作用のためにだけ実行され, ループ本体は空文です。繰返し文についての詳細は,第7.6節を参照してください。

空文は,複文を終了させる中括弧の直前にラベルが必要な場合にも役立ちます。 ラベルは,右中括弧の直前に付けることはできません。必ず文に付加する必要があります。 次にその例を示します。

     if (expression1)
     {
       ...

       goto label_1;  /* Terminates this part of the if statement */
       ...

     label_1: ;
     }
     else ...

7.5 選択文

選択文は制御式の値に応じて一連の文の中から文を選択します。 選択文には if文と switch文があります。これ以降の項では,これらの文について説明します。

7.5.1 if文

if文の構文は次のとおりです。

   if ()
   else(opt)

      文(opt)

制御式の値が真(0以外)の場合には,制御式に続く文が実行されます。 if文にオプションの else句を付けて記述すると, 制御式の値が偽(0)の場合にこの else句が実行されます。

次にその例を示します。

     if (i < 1)
        funct(i);
     else
        {
        i = x++;
        funct(i);
        }

この例では,i の値が1未満の場合には funct(i)文が実行され,elseキーワードに続く複文は実行されません。 i の値が1未満ではない場合には, elseキーワードに続く複文だけが実行されます。

選択文中の制御式は通常は論理式ですが,スカラ型であればどんな式でも構いません。

if文がネストされている場合,else句は同じブロック内にある else句を持たない直前の if文と対になります。次にその例を示します。

     if (i < 1)
         {
         if (j < 1)
             funct(j);
         if (k < 1)            /* This if statement is associated with */
             funct(k);
         else                  /* this else clause.                    */
             funct(j + k);
         }

7.5.2 switch文

switch文は,制御式の値に基づいて1つまたは複数の一連の文を実行します。

switch文の構文は次のとおりです。

   switch

通常の算術型変換は制御式で行われますが,その結果は汎整数型でなければなりません。 データ型変換についての詳細は第6.11節を参照してください。 switch文は一般に複文であり, 制御式が caseラベルと一致した場合に1 つまたは複数の case 文が実行されます。

caseラベルおよび式の構文は次のとおりです。

   case 定数式 : 

定数式は汎整数型でなければなりません。2つの caseラベルに同じ値を指定することはできません。 switch文中の caseラベルの数に制限はありません。

複文中で次のラベルを持つことができるのは,1つの文だけです。

   default :

case および defaultラベルの順序は決まっていませんが, 通常は case文の後に default文を続けます。break文を指定しない限り, 選択した文から順番に処理が実行されます。

switch文を実行すると,次の順序で処理が行われます。

  1. switch制御式が評価され(さらに汎整数拡張が適用され) ,caseラベル中の定数式と比較されます。

  2. 制御式の値が caseラベルと一致した場合には, 制御はこのラベルに続く文へ渡されます。 break文が見つかると,switch文は終了します。 それ以外の場合には,実行は次の case文または default文へ続き, break文または switch文の終わりが見つかると終了します( 例 7-1を参照してください)。

    switch文は,return文または goto文でも終了することができます。 switch文がループの内側にある場合には, continue文がループを終了すると switch文は終了します。これらの文についての詳細は, 第7.7節を参照してください。

  3. 制御式の値がどの caseラベルとも一致せず, defaultラベルがある場合に制御はこのラベルに続く文へ渡されます。 break文で default文が終了せず,case ラベルが続く場合はその case文が実行されます。

  4. 制御式の値がどの caseラベルとも一致せず, defaultラベルがない場合には switch文の実行は終了します。

例 7-1では,switch文を使用して, ターミナルから入力した空白,タブ,および改行文字の数をカウントします。

例 7-1 switch文を使用した空白,タブ,および改行のカウント

/*  This program counts blanks, tabs, and new lines in text *
 *  entered from the keyboard.                              */

#include <stdio.h>
main()
{
   int number_tabs = 0, number_lines = 0, number_blanks = 0;
   int ch;
   while((ch = getchar()) != EOF)
      switch (ch)
         {
            case '\t': ++number_tabs;             【1】
                         break;
            case '\n':  ++number_lines;           【2】
                        break;
            case ' ' :  ++number_blanks;
                        break;
            default:;
         }
   printf("Blanks\tTabs\tNewlines\n");
   printf("%6d\t%6d\t%6d\n", number_blanks,
                             number_tabs,number_lines);
}

次は,例 7-1の説明です。

  1. 一連の case文を使用して,入力された文字に応じて別々のカウンタを増分します。

  2. break文によって,制御は whileループに戻ります。ch の値がどの case定数式とも一致しない場合には, 制御は whileループへ渡されます。

break文がない場合には,次の case文が続けて実行されます。

変数宣言が switch文の中の複文に現れた場合には, auto または register宣言への初期値は無効になります。ただし, case文に続く文の中の初期化は有効です。次にその例を示します。

     switch (ch)
        {
           int nx = 1;          /* Initialization ignored            */
           printf("%d", n);     /* This first printf is not executed */
           case 'a' :
            { int n = 5;        /* Proper initialization occurs      */
              printf("%d", n);
              break; }
           case 'b' :
              { break; }
           default:
              { break; }
        }

この例で ch == 'a' の場合はプログラムは 5 を出力します。変数が他の文字と等しい場合にはプログラムは何も出力しません。 これは, caseラベルの外側の初期化および文は無効だからです。

7.6 繰返し文

繰返し文,すなわちループは制御式が偽(0)になるまでループ本体 の文を繰り返し実行します。制御式はスカラ型でなければなりません。

while文は,ループ本体を実行する前に制御式を評価します( 第7.6.1項を参照してください)。

do文は,ループ本体を実行した後に制御式を評価します。 したがって,ループ本体は必ず1回は実行されます(第7.6.2項を参照してください)。

for文は,3つの式の中の2番目の式の評価に基づいてループ本体を実行します( 第7.6.3項を参照してください) 。

7.6.1 while文

while文は,ループ本体の各実行の前に制御式を評価します。 制御式が真(0以外)の場合はループ本体が実行され,偽(0)の場合は while文は終了します。while文の構文は次のとおりです。

   while (  )

次に while文の例を示します。

     n = 0;
     while (n < 10)
        {
           a[n] = n;
           n++;
        }

この文は n の値を検査します。 n が10未満の場合は,a配列の n番目の要素に n を割り当てて,n を増分します。次に,(括弧内の) 制御式を評価します。真(0以外)の場合はループ本体が再び実行され, 偽(0)の場合は while文は終了します。 n++がループ本体にない場合には,この while文は終了することはありません。この例の n = 0 の文を n = 10 の文に置き換えると,この制御式は最初から偽(0)になり,ループ本体が実行されることはありません。

7.6.2 do文

do文は,ループ本体の各実行の後に制御式を評価します。

do文の構文は次のとおりです。

   do
      while ;

ループ本体は少なくとも1回は実行されます。制御式は, ループ本体の各実行の後に評価されます。制御式が真(0 以外)の場合は文が再び実行され,偽(0)の場合は do文は終了します。

7.6.3 for文

for文は3つの式を評価し,2番目の制御式の評価が偽(0)になるまでループ本体を実行します。 for文は,ループ本体を指定回数だけ実行する場合に役に立ちます。 for文の構文は次のとおりです。

   for (  1(opt) ; 2(opt) ;  3(opt))

for文は次のコードと等価です。

 1 ;
   while ( 2 )

      {3 ;
      }      

for文はループ本体を0回以上実行します。セミコロン( ; )を使用して,制御式を区切ります。 for文は次の処理を行います。

  1. 式1は,ループの最初の繰返しの前に1回評価されます。 この式は通常,ループ中で使用する変数の初期値を指定します。

  2. 式2は,ループを終了するかどうかを決めるスカラ式です。 式2は各ループの繰返しの前に評価されます。式が真(0 以外)の場合はループ本体が実行され,偽(0)の場合は for文の実行は終了します。

  3. 式3は各繰返しの後に評価されます。

  4. for文は式2が偽(0)になるまで,あるいは break または goto などの飛越し文でループの実行を終了するまで実行されます。

forループ内の3つの式はいずれも省略できます。次にその例を示します。

relaxed ANSI Cモードでは,for文の最初の句で, forヘッダの残りの句とループ本体をスコープとする宣言を行うことができます。 通常この句は,ローカルなループ制御変数の宣言と初期化に使用します。 次の例を参照してください。
for (int i=0; i<10; i++) 
    printf("%d\n", i); 

7.7 飛越し文

飛越し文は,コード内の別の場所にある別の文への無条件飛越しを引き起こします。 飛越し文は主に,switch文およびループの割込みに使用されます。

飛越し文とは,goto文,continue文,break文, および return文です。これ以後の各項では,これらの文について説明します。

7.7.1 goto文

ラベル識別子がその goto文を含む関数のスコープにある場合, goto文はプログラム制御をそのラベル付き文に無条件に渡します。 次に,制御を渡されたラベル付き文が実行されます。 goto文の構文は次のとおりです。

   goto 識別子;

goto文を使用してブロックに分岐する際には,注意する必要があります。 つまり,ブロックの呼出し時には,そのブロック内で宣言された自動変数に対して記憶域が割り当てられるのに対して, goto文でブロックに分岐すると,そのブロック内で宣言された自動変数は初期化されないからです。

7.7.2 continue文

continue文は,それを直接囲んでいる whiledo,または for文のループの終わりに制御を渡します。 continue文の構文は次のとおりです。

   continue ;

continue文は,ループ本体の終わりに制御を渡す繰返し文の中の goto文と同じです。たとえば,次の2つのループは同じです。

     while(1)                           while(1)
     {                                  {
        .                                  .
        .                                  .
        .                                  .
       goto label_1;                     continue;
        .                                  .
        .                                  .
        .                                  .
       label_1:
        ;                                  ;
      }                                  }

continue文はループ内でのみ使用できます。 ループの内部にあるswitch文に continue 文がある場合には,continue文は switch文の本体が終了し,外側のループの処理を続行します。

7.7.3 break文

break文は,それを直接囲んでいる whiledo,または switch文の実行を終了します。制御はループ本体に続く文( または switch文の複文)へ渡されます。 break文の構文は次のとおりです。

   break ;

switch文の中での break文の使用例については, 例 7-1を参照してください。

7.7.4 return文

return文は関数の実行を終了し,制御を返却値とともにまたは返却値なしで呼出し関数に返します。 関数に含まれる return文の数に制限はありません。

return文の構文は次のとおりです。

   return 式(opt);

式が存在する場合はその式は評価され,その値が呼出し関数へ返されます。 その値は必要に応じて,それを含む関数の返却値に宣言されている型へ変換されます。

式を持つ return文は,返却値の型が void の関数には指定することはできません。 voidデータ型および関数の返却値の型についての詳細は, 第3.5節 第3.4.1項を参照してください。

式が存在しない場合で関数が void として定義されていなければ, 返却値の型も定義されていません。たとえば, 次の main関数は予測できない値をオペレーティング・ システムに返します。

     main ( )
       {
        return;
       }

関数を終了する右中括弧に達すると,式を持たない return文を実行することになります。