C言語入門 第12回 制御文制御文(if、for、while、switchなど)
2014年10月より個人の方を対象に、Study C無料提供を開始しました。
C言語を勉強中の方は、学習・教育に最適なC言語インタープリタのStudy Cを使ってみてください(個人の方は無料です)。
大学・高専・高校などの教育機関での採用実績も多数あるロングセラー商品Study Cが、個人向けに無料提供を始めました。
インタープリタの手軽さに加え、ゲームや3Dタートルグラフィックで楽しく勉強したりと、C言語の学習を強力にサポートします。
また、このようなボタンの用意されているページでは、掲載しているプログラムをStudy Cに直接ロードし実行したりすることができます。
Study C無料利用についての詳細は、このページを参照してください。
制御文とは、実行の流れを変化させるものをさします。今までの説明の中でif文とfor文がこの制御文にあたります。一方、a = a+1;といったような式では実行の流れがいつも変化しません。C言語には、if、for文の他にもいくつかの制御文があります。
C言語の制御文 if 条件 if...else... 条件 for ループ while ループ do...while ループ switch(case、default) 選択 goto ジャンプ return 関数からの戻り break 制御文からの抜け出し continue ループの続行
今までに説明した制御文だけでも十分プログラムを作ることが可能ですが、残りの 制御文についても一通り説明しておきます。
ループ制御文はfor文で説明した繰り返しを行うための制御文です。前のC言語入門ではfor文を 次のような形式で説明しました。
for (変数 = 0; 変数 < 繰り返しの回数; 変数++) { 繰り返し実行したい内容 }
しかし、実際には、変数 = 0 といったように決まった型の式を使う必要はなく、自由な式が使用可能です。したがって、for文の形式は次のようになります。
for (式1; 条件; 式2) { 繰り返し実行したい内容 }
式1はループを初めに1回だけ実行され、式2は1回のループごとに実行されます。また、前にも述べたように式や条件は省略することが可能で、次の2つはまったく同じ動作をします。
for (式1; 条件; 式2) { 繰り返し実行したい内容 } ↓ 式1; for (; 条件;) { 繰り返し実行したい内容 式2; }
0から9まで表示する簡単なループのプログラムを2通りの方法に作ってみましょう。
main() { int i; for (i = 0; i < 10; i++) { printf("%d ", i); } }
0 1 2 3 4 5 6 7 8 9
main() { int i; i = 0; for (; i < 10; ) { printf("%d ", i); i++; } }
0 1 2 3 4 5 6 7 8 9
両方のプログラムは同じ実行結果になります。
while文はfor文の式1と式2の機能を削ったもので、条件のみを指定します。
while (条件) { 繰り返し実行したい内容 }
また、次のようにfor文とまったく同じ動作をさせることもできます。
for (;条件 ;) { while (条件) { 繰り返し実行したい内容 = 繰り返し実行したい内容 } } for (式1; 条件; 式2) { 式1; 繰り返し実行したい内容 = while (条件) { } 繰り返し実行したい内容 式2; }
このように、while文はfor文に極めて類似しているため、簡単に理解することができると思います。また、0から9まで表示するプログラムは次のようになります。
main() { int i; i = 0; while (i < 10) { printf("%d ", i); i++; } }
0 1 2 3 4 5 6 7 8 9
do...while文は次の形式で使用します。
do { 繰り返し実行したい内容 } while (条件); (←ここには必ずセミコロンが必要です)
do...while文はwhile文に類似しています。両者の相違点はループの条件を評価する場所が異なっていることです。while文はfor文と同じく最初に繰り返しを行うか条件を評価します。それに対しdo...while文は、とりあえず1回だけは内容を実行して最後に繰返しを続けるか条件を評価します。do...while文を使って0から9までの表示を行うプログラムは次のようになります。
main() { int i; i = 0; do { printf("%d ", i); i++; } while (i < 10); }
0 1 2 3 4 5 6 7 8 9
break、continue文は単独で使用することはできず、他の制御文と組み合わせて使用します。
(1)breakと組み合わせて使用する制御文 for while do...while switch (2)continueと組み合わせて使用する制御文 for while do...while
continue文は必ずループ制御文の中で使用します。ループ内でcontinue文が実行されると、残りの行は実行されずに次の回のループに移行します。
for (;;) { この部分は実行される . . . continue; この部分は実行されない . . . 実行位置がループの最後に移行するので、結果的に次の回のループ が開始される。 }
このように、continue文以後の行は実行されずにループします。
main() { int i; for (i = 0; i < 5; i++) { printf("%d ", i); continue; printf("test"); } }
0 1 2 3 4
もし、このプログラムでcontinue文がなければprintf("test");も実行され、実行結果は次のようになるはずです。
0 test 1 test 2 test 3 test 4 test 5 test
continue文を、この例のように使っても意味がありません。continue文はループ内でif文か、後で述べるswitchと組み合わせて使用するのが普通です。次の例がif文とcontinue文を組み合わせた例です。
main() { int i; for (i = 0; i < 10; i++) { printf("%d", i); if (i%2 == 0) { continue; } printf(" KISUU "); } }
01 KISUU 23 KISUU 45 KISUU 67 KISUU 89 KISUU
このプログラムは、ループ内で0から9まで表示させながら奇数のときはKISUUと表示するプログラムです。if (i%2 == 0)はiを2で割った余りが0ならばcontinueするという意味のif文です。continue文もwhileやdo...while文と同じく、プログラムに不可欠なものではありません。たとえば、前の例もif文の使い方を「iを2で割った余りが1ならばKISUUと表示する」とすれば、continue文を使わずに同じ結果になります。
main() { int i; for (i = 0; i < 10; i++) { printf("%d", i); if (i%2 == 1) { printf(" KISUU "); } } }
01 KISUU 23 KISUU 45 KISUU 67 KISUU 89 KISUU
break文はループ内かswitch文(後述)の中で使用します。break文が実行されるとループやswithの動作を中断します。
for (;;) { この部分は実行される . . . break; この部分は実行されない . . . } ループなどを中断して実行位置はここへ移動
break文もcontinue文と同じようにif文と組み合わせて使わないと意味がありません。break文を作って0から9まで表示するプログラムは次のようになります。
main() { int i; for (i = 0;; i++) { printf("%d ", i); if (i >= 9) { break; } } }
0 1 2 3 4 5 6 7 8 9
この例はbreak文とif文を組み合わせて使っていますが、for文の条件を省略する程度の意味しかありません。break文とループを有効に利用した例を次に示します。
main() { int i, len; char str[100]; printf("INPUT:"); scanf("%s", str); len = strlen(str); for (i = 0; i < len; i++) { if (str[i] == 'G') { printf("%d\n", i); break; } } }
INPUT:STRING TEST 5
このプログラムは、入力した文字列の中から大文字のGを見つけだし、何文字目かを 表示するものです。ループ内で0文字目から順番に大文字のGと比較し、見つかった時点で その位置を表示し、break文を実行してループを終了させています。また、比較するのは 入力した文字列の長さだけでよいので、これをループの条件に使用しています。
goto文は実行位置を移動させます。gotoの後ろにはラベルを書き、そのラベルの場所に移動します。移動できる場所は同じ関数内に限られます。
Label: goto Label;
また、ラベルには次のような規則があります。
(1)ラベルは変数名と同じ規則で表現します。
(2)ラベルは変数宣言の前や途中には使用できません。
(3)ラベルは中カッコ}の直前には使用できません。もし、使用したい場所はラベルの
後ろにセミコロン;を付加します。
|
C言語ではプログラムが見づらくなるため、goto文はなるべく使用しません。たとえば、 forループをgoto文で表現すると次のようになります。
例1) for (i = 0; i < 10; i++) { . . . } ↓ i = 0; LABEL1: if(i >= 10) goto LABEL2; . . . i++; goto LABEL1; LABEL2: 例2) for (i = 0; i < 10; i++) { for (j = 0; j < 10; j++) { . . . } } ↓ i = 0; LABEL1: if (i >= 10) goto LABEL4; j = 0; LABREL2: if (j >= 10) goto LABEL3 . . . j++; goto LABEL2 LABEL3: i++; goto LABEL1: LABEL4:
このようにgoto文の数が増えるとプログラムは理解しづらくなります。goto文の飛び先が入り組んだプログラムをスパゲティプログラムと呼んだりします。
L2: goto L1; L4: goto L3; . . . goto L2; L1: . . . goto L4; L3: . . .
それでは、C言語ではどのような場所でgoto文を使うのでしょうか。実際、goto文をまったく使用しなくてもプログラミングは可能です。強いて使う場所といえば、次のような場合です。
for (...) { for (...) { . . . if (...) { ある条件が満たされたのでループを終了させたい } } }
このような場合、break文でループを終了させることもできますが、breakは1つのループしか終了させることができません。また、条件が満たされなかったときに何か処理を行わなければならない場合などは、次のようにgoto文を使用してもよいでしょう。
for (...) { for (...) { . . . if (...) { 条件が満たされた場合の処理 goto LABEL; } . . . } } 条件が満たされなかった場合の処理 LABEL:
このように、goto文はループなどの制御文が何重にも合わさった所から一度で抜け出す ような場合に有効です。また、これとは逆にループなどの中へgoto文で飛び込むこともで きますが、これは極めて非常識なgoto文の使い方です。
switch文は変数の値に応じて処理を選択するために使用します。switch文は、次の形式で使用します。
switch(式){ case定数1: 式の値が定数1に等しいときに実行する内容 break; case定数2: . . . default: 式の値が上記のすべての定数のどれにも一致しないときに 実行する内容 break; }
定数は何個でも指定することができます。また、defaultは省略することも可能です。 switch文を使った例を示します。
main() { int i; printf("INPUT:"); scanf("%d", &i); switch (i) { case 1: printf("one"); break; case 2: printf("two"); break; case 3: printf("three"); break; default: printf("difficult"); break; } }
INPUT:2 two
このプログラムは数字を入力するとそれに応じた英語を表示しますが、4以上の場合は すべてdifficultと表示されます。この例ではcase...break;と定形的な構成になって いますが、次のような使い方も可能です。
main() { int i; printf("INPUT:"); scanf("%d", &i); switch (i) { case 9: case 7: case 5: printf("i >= 5\n"); case 3: case 1: printf("KISUU"); break; default: printf("GUUSUU"); break; } }
INPUT:7 i >= 5 KISUU
このプログラムは入力した数字が奇数ならKISUU、偶数ならGUUSUUと表示させます。
また、KISUUで5以上ならあわせてi >= 5とも表示します。
最後にswitch文を使用する場合の注意点を示します。
(1)caseに使える数は定数だけで、変数は使用することができません。ただし、case 1+2:
のような定数を組み合わせた式は使用することができます。
(2)caseと定数の間の空白を入れ忘れるとcase1:などとなってしまい、goto文で使用するラベルとして処理されてしまいます。また、default:のスペルを間違えても同じ結果になります。
この間違いは(1)と違いエラーにならないため発見が困難です。十分注意してください。