この章では,Cプログラミング言語における次の種類の文について説明します。 この章で示す文以外の文は,関数本体に現れる順序で実行されます。
ラベルは,goto
文または switch
文の行き先として,
プログラム内のある位置にフラグを立てる際に使用する識別子です。
その構文は以下のとおりです。
識別子 : 文 case 定数式 : 文 default : 文
ラベルのスコープはそのラベルを含んでいる関数本体です。変数には, 関数内のラベルと同じ名前をつけることができます。これは,ラベルと変数の名前空間が異なるからです。 第2.15 節を参照してください。
C言語のラベル付き文には,次の3種類があります。
case
文
default
文
case
文と default
文は,
switch
文の中にのみ指定します。第7.5.2項を参照してください。
複文,すなわちブロックは一連の文を単一の文として 扱うことができます。 複文は左中括弧で開始し, 宣言と文を任意の順で含み,右中括弧で終了します。次にその例を示します。
{ int a; a = 1; int b; b = 2; }
ブロック宣言は各ブロック内でのみ有効であり,そのブロック内では外側のスコープで宣言されている同じ名前の他の宣言に優先します。
制御フローがブロックに入るか,または goto
文がそのブロックの始めのラベルに制御を渡すと,
そのブロックは正常に開始されます。
ブロックが正常に開始されるたびに,auto
または register
変数に対して記憶域が割り当てられます。
これに対して
goto
文が制御をブロック内のラベルに渡した場合,
またはブロックが switch
文の本体である場合にはこの記憶域の割当ては行われません。記憶域クラスについての詳細は,
第2.10節を参照してください。
関数定義は複文を含んでいます。関数定義において,仮引数宣言に続く複文を関数本体と呼びます。
式の後にセミコロンを付けることによって,有効な式を文として使用することができます。 次にその例を示します。
i++;
この文は,i
変数の値を増分します。
i++
はC言語の複雑な文にも現れるC言語の有効な式です。C
言語の式についての詳細は,第6章を参照してください。
空文は,C言語の文法により文を必要とする場合に空演算を行う際に使用されますが, プログラム中で特に作業を行う必要はありません。空文はセミコロンで構成されます。
空文は
if
,while
,do
,および
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 ...
選択文は制御式の値に応じて一連の文の中から文を選択します。
選択文には if
文と
switch
文があります。これ以降の項では,これらの文について説明します。
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); }
switch
文は,制御式の値に基づいて1つまたは複数の一連の文を実行します。
switch
文の構文は次のとおりです。
switch 文
通常の算術型変換は制御式で行われますが,その結果は汎整数型でなければなりません。
データ型変換についての詳細は第6.11節を参照してください。
switch
文は一般に複文であり,
制御式が case
ラベルと一致した場合に1
つまたは複数の case
文が実行されます。
case
ラベルおよび式の構文は次のとおりです。
case 定数式 : 文
定数式は汎整数型でなければなりません。2つの
case
ラベルに同じ値を指定することはできません。
switch
文中の case
ラベルの数に制限はありません。
複文中で次のラベルを持つことができるのは,1つの文だけです。
default :
case
および
default
ラベルの順序は決まっていませんが,
通常は case
文の後に
default
文を続けます。break
文を指定しない限り,
選択した文から順番に処理が実行されます。
switch
文を実行すると,次の順序で処理が行われます。
switch
制御式が評価され(さらに汎整数拡張が適用され)
,case
ラベル中の定数式と比較されます。
case
ラベルと一致した場合には,
制御はこのラベルに続く文へ渡されます。
break
文が見つかると,switch
文は終了します。
それ以外の場合には,実行は次の
case
文または default
文へ続き,
break
文または switch
文の終わりが見つかると終了します(
例 7-1を参照してください)。
switch
文は,return
文または
goto
文でも終了することができます。
switch
文がループの内側にある場合には,
continue
文がループを終了すると
switch
文は終了します。これらの文についての詳細は,
第7.7節を参照してください。
case
ラベルとも一致せず,
default
ラベルがある場合に制御はこのラベルに続く文へ渡されます。
break
文で
default
文が終了せず,case
ラベルが続く場合はその case
文が実行されます。
case
ラベルとも一致せず,
default
ラベルがない場合には
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の説明です。
case
文を使用して,入力された文字に応じて別々のカウンタを増分します。
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
ラベルの外側の初期化および文は無効だからです。
繰返し文,すなわちループは制御式が偽(0)になるまでループ本体 の文を繰り返し実行します。制御式はスカラ型でなければなりません。
while
文は,ループ本体を実行する前に制御式を評価します(
第7.6.1項を参照してください)。
do
文は,ループ本体を実行した後に制御式を評価します。
したがって,ループ本体は必ず1回は実行されます(第7.6.2項を参照してください)。
for
文は,3つの式の中の2番目の式の評価に基づいてループ本体を実行します(
第7.6.3項を参照してください)
。
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)になり,ループ本体が実行されることはありません。
do
文は,ループ本体の各実行の後に制御式を評価します。
do
文の構文は次のとおりです。
do 文 while ;
ループ本体は少なくとも1回は実行されます。制御式は,
ループ本体の各実行の後に評価されます。制御式が真(0
以外)の場合は文が再び実行され,偽(0)の場合は
do
文は終了します。
for
文は3つの式を評価し,2番目の制御式の評価が偽(0)になるまでループ本体を実行します。
for
文は,ループ本体を指定回数だけ実行する場合に役に立ちます。
for
文の構文は次のとおりです。
for ( 式 1(opt) ; 式 2(opt) ; 式 3(opt)) 文
for
文は次のコードと等価です。
式 1 ;
while ( 式2 ) { 文 式3 ; }
for
文はループ本体を0回以上実行します。セミコロン(
; )を使用して,制御式を区切ります。
for
文は次の処理を行います。
for
文の実行は終了します。
for
文は式2が偽(0)になるまで,あるいは
break
または
goto
などの飛越し文でループの実行を終了するまで実行されます。
for
ループ内の3つの式はいずれも省略できます。次にその例を示します。
while
ループの等価は
while(1)
になります。これは無限ループです。
次にその例を示します。
for (i = 0; ;i++) 文;
無限ループはループ本体内の
break
,return
,または
goto
文で終了させることができます。
for
文から省略すると,
省略した式は void
式として評価され,
実際の展開からは除外されます。次にその例を示します。
n = 1; for ( ; n < 10; n++) func(n);
この例では,n
は
for
文が実行される前に初期化されます。
for
文の最初の句で,
for
ヘッダの残りの句とループ本体をスコープとする宣言を行うことができます。
通常この句は,ローカルなループ制御変数の宣言と初期化に使用します。
次の例を参照してください。
for (int i=0; i<10; i++) printf("%d\n", i);
飛越し文は,コード内の別の場所にある別の文への無条件飛越しを引き起こします。
飛越し文は主に,switch
文およびループの割込みに使用されます。
飛越し文とは,goto
文,continue
文,break
文,
および return
文です。これ以後の各項では,これらの文について説明します。
ラベル識別子がその goto
文を含む関数のスコープにある場合,
goto
文はプログラム制御をそのラベル付き文に無条件に渡します。
次に,制御を渡されたラベル付き文が実行されます。
goto
文の構文は次のとおりです。
goto 識別子;
goto
文を使用してブロックに分岐する際には,注意する必要があります。
つまり,ブロックの呼出し時には,そのブロック内で宣言された自動変数に対して記憶域が割り当てられるのに対して,
goto
文でブロックに分岐すると,そのブロック内で宣言された自動変数は初期化されないからです。
continue
文は,それを直接囲んでいる
while
,do
,または
for
文のループの終わりに制御を渡します。
continue
文の構文は次のとおりです。
continue ;
continue
文は,ループ本体の終わりに制御を渡す繰返し文の中の
goto
文と同じです。たとえば,次の2つのループは同じです。
while(1) while(1) { { . . . . . . goto label_1; continue; . . . . . . label_1: ; ; } }
continue
文はループ内でのみ使用できます。
ループの内部にあるswitch
文に
continue
文がある場合には,continue
文は
switch
文の本体が終了し,外側のループの処理を続行します。
break
文は,それを直接囲んでいる
while
,do
,または
switch
文の実行を終了します。制御はループ本体に続く文(
または switch
文の複文)へ渡されます。
break
文の構文は次のとおりです。
break ;
switch
文の中での break
文の使用例については,
例 7-1を参照してください。
return
文は関数の実行を終了し,制御を返却値とともにまたは返却値なしで呼出し関数に返します。
関数に含まれる
return
文の数に制限はありません。
return
文の構文は次のとおりです。
return 式(opt);
式が存在する場合はその式は評価され,その値が呼出し関数へ返されます。 その値は必要に応じて,それを含む関数の返却値に宣言されている型へ変換されます。
式を持つ return
文は,返却値の型が
void
の関数には指定することはできません。
void
データ型および関数の返却値の型についての詳細は,
第3.5節 と第3.4.1項を参照してください。
式が存在しない場合で関数が void
として定義されていなければ,
返却値の型も定義されていません。たとえば,
次の main
関数は予測できない値をオペレーティング・
システムに返します。
main ( ) { return; }
関数を終了する右中括弧に達すると,式を持たない
return
文を実行することになります。