第17回 if~elseの入れ子(いれこ),goto文,論理演算子

このドキュメントは http://icrus.org/c_language_beginers_course/ 上にあります.

プログラムが少しずつ高度になってくると,必ずといって良いほどif~else文の入れや,goto文,複雑な論理演算子の組み合わせが登場してきます.ここではやや複雑なプログラム例を見て,それらについて説明します.

[課題17-1] 条件文を駆使してプログラムリストの識別子だけを選んで出力しよう.

[プログラム例17-1]


01: #include <stdio.h>
02: #include <stdlib.h>
03: #include <process.h>
04: #include <ctype.h>
05: #define  FILENAME "a:\\tmp.c"
06:
07: void main(void){
08:     FILE *fp;
09:     int  c, chk;
10:
11:     if( (fp=fopen( FILENAME, "rt" ))==NULL ){
12:         printf( "file open error:%s\n", FILENAME );
13:         exit(1);
14:     }
15:
16:     chk = 1;
17:     while( (c=fgetc(fp))!=EOF ){
18:         if( c=='\'' ){
19:             if( chk==0 )
20:                 putchar( ' ' );
21:             chk = 1;
22:             do{
23:                 c = fgetc( fp );
24:                 if( c=='\\' ){
25:                     c = fgetc( fp );
26:                     if( c=='\'' )
27:                         c = fgetc( fp );
28:                 }
29:                 if( c==EOF )
30:                     goto file_end;
31:                 }while( c!='\'' );
32:             }else if( c=='\"' ){
33:             if( chk==0 )
34:                 putchar( ' ' );
35:             chk = 1;
36:             do{
37:                 c = fgetc( fp );
38:                 if( c=='\\' ){
39:                     c = fgetc( fp );
40:                     if( c=='\"' )
41:                         c = fgetc( fp );
42:                 }
43:                 if( c==EOF )
44:                     goto file_end;
45:             }while( c!='\"' );
46:         }else if( isalpha(c) || isdigit(c) || c=='_' || c=='.' ){
47:             chk = 0;
48:             putchar( c );
49:         }else{
50:             if( chk==0 ){
51:                 putchar( ' ' );
52:             }
53:             chk = 1;
54:         }
55:     }
56:
57:     file_end:
58:     if( fclose( fp )==EOF ){
59:         printf( "file close error:%s\n", FILENAME );
60:         exit(1);
61:     }
62:     putchar( '\n' );
63:     putchar( '\n' );
64:     getch();
65: }


04行目 → 関数isalpha()などを使うために必要なインクルードファイルです.
05行目 → 入力するファイル名をマクロ定義してください.
17~56行 → ファイルの終わりまで,1文字づつ読み込むwhileループです.whileブロックの中は4ブロックからなるif~else文の入れ子になっています.
30,44行 → 条件が成立(関数fgetc()の戻り値がEOF)したとき,57行目のラベルfile_end:以降に制御が飛びます.
22~31行 → do~while文です.ブロックの最後に判定を行って,真ならdoブロックの先頭に戻ります.
46行目 → 関数isalpha(c)は,変数cがアルファベットの真.関数isdigit(c)は変数cが数字のとき真.これらの関数を使うために4行目のインクルードファイルctype.hが必要です.

[結果17-1]

コンパイル・実行すると次のよう表示されます.
include stdio.h include stdlib.h include process.h include ctype.h define FILENAME void main void FILE fp int c chk if fp fopen FILENAME NULL printf FILENAME exit 1 chk 1 while c fgetc fp EOF if c if chk 0 putchar chk 1 do c fgetc fp if c c fgetc fp if c c fgetc fp if c EOF goto file_end while c else if c if chk 0 putchar chk 1 do c fgetc fp if c c fgetc fp if c c fgetc fp if c EOF goto file_end while c else if isalpha c isdigit c c c chk 0 putchar c else if chk 0 putchar chk 1 file_end if fclose fp EOF printf FILENAME exit 1 putchar putchar getch
リターンキーを押すとプログラムは終了します.

 プログラム例17-1のソースファイルを入力として,識別子と数値を現れる順に出力しています.1対の"",1対の''で囲まれた文字列は出力しません.

~if~else文の入れ子構造について~

このプログラムは,①17~31行,②32~45行,③46~48行,④49~54行の4つのブロックからなるif~else文の入れ子になっています.基本的なif~else文の入れ子は次のようなものです.いくつでも連ねることができます.


if(条件式1){
    文1;
    :
}else if(条件式2){
    文2;
     :
}else if(条件式3){
    文3;
     :
}else{
    文4;
     :
}

制御は次のようになります.
(1)条件式1が真のとき文1を実行.残りの文2~4はスッキップして実行しない. (2)条件式1が偽のとき条件式2を評価して真のとき文2を実行する.残り文3~4実行しない.
(3)条件式2が偽のとき条件式3を評価して真のとき文3を実行する.文4は実行しない.
(4)最後に条件式1~3が偽のときは文4を実行する.
プログラム例17-1では,次の処理をしています.
①文字「'」の処理
②文字「"」の処理
③アルファベット,数字,文字「_」,文字「.」の処理
④その他の文字の処理
 ①ブロックでは,chk==0のときあったとき,区切りの空白文字を出力します.文字「'」を読み込むまでファイルを空読みします.変数chkに1を代入します.
 ②ブロックでは,chk==0のときあったとき,区切りの空白文字を出力します.文字「"」を読み込むまでファイルを空読みします.変数chkに1を代入します.
③ブロックでは,変数chkに0を代入します.変数cを出力します.
 ④ブロックでは,chk==0のときあったとき,区切りの空白文字を出力します.変数chkに1を代入します.
 その他,①②ブロックでは,「'\''」(文字「'」)や「"\""」(文字列の中の文字「"」)にも対応するようになっています.

~goto文について~

30行目から57行目へ,44行目から57行目へgoto文があります.基本的にはgoto文は次のようになります.条件文などと組み合わせて,強制的にラベル:以降の文へ制御を移します.C言語には,多くの優れた制御構造がありますので,goto文はエラー処理など,2重ループを抜けるときだけに使用すべきです.むやみに使用するとわかりにくいプログラムになってしまいます.

goto ラベル;
:
ラベル:
文;

~論理演算子について~

46行目を見て下さい.
条件式( isalpha(c) || isdigit(c) || c=='_' || c=='.' )
条件式のあいだに演算子「||」があります.これは論理和「or」の意味で使われます.この条件式は「関数isalpha(c)が真,またはisdigit(c)が真,またはc=='_'が真,またはc=='.'が真」のとき真となります.論理演算子についてまとめるとつぎのようになります.

演算子 働き 意味



!a 否定(not) 真を偽に,偽を真に変える.
a && b 論理積(and) aかつb(a ∩ b)
a || b 論理和(or) aまたはb(a ∩ b)

[文法17]

1.if~else文の入れ子



if(条件式1){
    文1;
     :
}else if(条件式2){
    文2;
     :
}else if(条件式3){
    文3;
     :
}else{
    文4;
     :
}


(1)制御は次のようになります.
①条件式1が真のとき文1を実行.残りの文2~4はスッキップして実行しない.
②条件式1が偽のとき条件式2を評価して真のとき文2を実行する.残り文3~4実行しない.
③条件式2が偽のとき条件式3を評価して真のとき文3を実行する.文4は実行しない.
④最後に条件式1~3が偽のときは文4を実行する.
(2)ブロックをいくつ連ねても構いません.

2.goto文

goto ラベル;
:
ラベル:
文;
①条件文などと組み合わせて,強制的にラベル:以降の文へ制御を移します.
②C言語には,多くの優れた制御構造がありますので,goto文はエラー処理など,2重ループを抜けるときだけに使用すべきです.むやみに使用するとわかりにくいプログラムになってしまいます.

3.論理演算子について

演算子 働き 意味 優先順位



!a 否定(not) 真を偽に,偽を真に変える. 1
a && b 論理積(and) aかつb(a ∩ b) 2
a || b 論理和(or) aまたはb(a ∩ b) 3

(1)以上に示した.3つの論理演算子があります.
(2)優先順位を変えたいときは四則演算子同様に()を使って下さい.





このドキュメントは http://icrus.org/c_language_beginers_course/ 上にあります.

2017,1 ssatoh@ 足立工科大学 工学部 情報通信工学科