プログラムの流れの制御は, if, switch, for, while, do ... while があれば十分であり, C言語にはこれらが備わっている. ここでは, そのうちの2つ ifとswitchについて学ぶ.
if および switch を用いたプログラムを作成する. 3.5を参考にしてもよい.
作成したプログラム(.cが付くファイル)をメールで提出する. 本文に, 学籍番号, 氏名を明記すること.
if ( condition ) { 文A1; 文A2; 文A3; } else { 文B1; 文B2; 文B3; }において 条件式 condition が真のとき, if に続く{ } で囲まれたブロック内の文 文A1, 文A2, 文A1 が順に実行される. このとき 文B1, 文B2, 文B3 を含むelse に続くブロックは実行されない. 逆に 条件式 condition が偽のとき, else 以降の { } で囲まれたブロック内の文 文B1, 文B2, 文B3 が実行される. このとき 文A1, 文A2, 文A3 は実行しない.
ブロック内の文は複数であっても構わないし, 1文のみでも構わない. (さらに ;のみからなる何も実行しない文 空文 でも構わない.)
例
#include <stdio.h> int main(void) { int a = 3; if ( a > 3) { puts("aは3より大きい."); } else { puts("aは3と等しいか小さい."); } return 0; }
文法的には以下のように { および } を配置しても構わない. 慣れないうちはこちらの方が見通しがいいかも知れないが, 慣習としては上の書き方が多用されている.
#include <stdio.h> int main(void) { int a = 3; if ( a > 3) { puts("aは3より大きい."); } else { puts("aは3と等しいか小さい."); } return 0; }
if ( condition ) { 文A1; 文A2; 文A3; }
#include <stdio.h> int main(void) { int a = 3; if ( a > 3 ) { puts("aは3より大きい."); } return 0; }
1つ目の else の後ろに
if ( a < 0 ) { puts("a は負です."); } else { puts("aは0です."); }を接続し, 第一の条件式 a>0 が偽のときさらに 条件式 a<0 により分岐できる.
#include <stdio.h> int main(void) { int a = 3; if ( a > 0 ) { puts("a は正です."); } else if ( a < 0 ) { puts("a は負です."); } else { puts("aは0です."); } }
次のようにさらに if を加えることもできる.
#include <stdio.h> int main(void) { int a = 3; if ( a > 10 ) { puts("a は10より大きい."); } else if ( a > 0 ) { puts("a は正です."); } else if ( a < 0 ) { puts("a は負です."); } else { puts("aは0です."); } }
if の条件式が真のとき, それに続く1文または1ブロックが実行される. ブロックは, { と } で囲まれた複数の文の集まりで, 前から順に評価・実行される.
/* このプログラムでは, aが3のとき, puts("aは3です");と puts("hello."); が実行される. */ #include <stdio.h> int main(void) { int a = 3; if ( a==3 ) { puts("aは3です."); puts("hello."); } return 0; }
ブロックは1つの文のみを含んでもよい. 次の例では, puts("hello.") はブロックに含まれていないので a == 3 の条件に関係なく常に実行される.
/* このプログラムでは, aが3のとき, puts("aは3です."); が実行される. また a の値に関係なく常に puts("hello."); が実行される. */ #include <stdio.h> int main(void) { int a = 3; if ( a==3 ) { puts("aは3です."); } puts("hello."); return 0; }
/* このプログラムでは, aが3のとき, puts("aは3です."); が実行される. また a の値に関係なく常に puts("hello."); が実行される. */ #include <stdio.h> int main(void) { int a = 3; if ( a==3 ) puts("aは3です."); puts("hello."); return 0; }
慣れないうちは 1文だけでもブロックにしておいた方が誤りが少なくてよい.
等価演算子 (教科書 Table 3-1)
名称 | C言語における表記 | 数学における表記 |
==演算子 |
a == b | ![]() |
!=演算子 |
a != b | ![]() |
関係演算子 (教科書 Table 3-2)
名称 | C言語における表記 | 数学における表記 |
<演算子 |
a < b |
![]() |
>演算子 |
a > b |
![]() |
<=演算子 |
a <= b |
![]() |
>=演算子 |
a >= b |
![]() |
論理演算子 (教科書 Table 3-4, Table 4-1) 条件式を組み合わせる時に用いる.
名称 | C言語における表記 | 意味 |
論理AND演算子 | A && B | 『条件式Aが真「かつ」条件式Bが真』のとき真 |
論理OR演算子 | A || B | 『条件式Aが真「または」条件式Bが真』のとき真 |
論理否定演算子*1 | ! A | Aの否定. 条件式Aが真のとき偽, 偽のとき真. |
数学で と表現されるような条件式は,
「3<a かつ a<8」のように2つの数の比較だけを組み合わせ
て表現する必要がある. この例では次のように (3<a) && (a<8) とする.
#include <stdio.h> #include <stdlib.h> int main(void) { int a; if ( (3 < a) && (a < 8) ) { puts("a は 3<a<8 を満たす."); }else{ puts("a は 3<a<8 を満たさない.."); } return EXIT_SUCCESS; }C言語でそのまま3<a<8と表記すると異なる意味になる. 比較した結果は真(整数の非0)か偽(整数の0)であり, a の値ではなくなってしまうからである. この例では, 優先順位の規則に従って左から評価されるので (3<a) < 8 が求められることになってしまう. ここでは, まず 3<a が評価されこれが非0となる. 次に非0 < 8 が比較され, それが真か偽の値を持つ.
#include <stdio.h> int main(void) { int a = 1, b = -3, c = 25; if( (a==1) && (b<0) ) puts("「aは1に等しく」 かつ 「b は負である.」"); if( (a>1) || (b>10) ) puts("「aは1より大きい」 または 「b は10より大きい.」"); if( ( (a>20) || (b>10) ) && (c<0) ) puts("『「aは20より大きい」 または 「b は10より大きい.」』 かつ 「cは0より小さい.」"); return 0; }
? : 教科書参照のこと.
例えば
#include <stdio.h> int main(void) { int a = 3; if ( a==1 ) puts("true"); return 0; }においては, a==1 は偽であるので 「a==1」 は 「0」 である. したがって, 次のプログラムと等価になる.
#include <stdio.h> int main(void) { int a = 3; if ( 0 ) puts("true"); return 0; }
規格では真の時条件式がいくつであるかは定められていないが, 次のようにして使用している環境でいくつになるかを調べられる.
#include <stdio.h> #include <stdlib.h> int main(void) { int a = 1, condition; condition = (a==3); printf("condistion=%d\n", condition); return EXIT_SUCCESS; }
このように条件式を入れる部分に整数を入れて, プログラムの制御を行うこともある. 次のプログラムでは, 無限にputs("hello"); を実行し続ける.
#include <stdio.h> int main(void) { while ( 1 ) { puts("hello"); } }
case から入り break; までを実行することに注意すること.
#include <stdio.h> int main(void) { int month = 3; switch (month) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: printf("%d月は31日まであります.\n", month); break; case 4: case 6: case 9: case 11: printf("%d月は30日まであります.\n", month); break; case 2: printf("%d月は28日または29日まであります.\n", month); break; default: printf("%d月はありません.\n", month); break; } return 0; }
#include <stdio.h> int main(void) { int i; i = 10; switch (i % 4) { case 0: printf("%dは4で割り切れます.\n", i); break; case 1: printf("%dを4で割ると1余ります.\n", i); break; case 2: case 3: printf("%dを4で割ると1以外の余りが出ます.\n", i); break; default: printf("この行が実行されることはありません.\n"); return 1; break; } return 0; } /* return 1; について main関数中で return 文を実行すると, その文でプログラムの実行を終了する. このプログラムのdefault での処理のように プログラムを異常終了させる場合は 0 以外の値を OS に return する場合が多い. どの値が正常終了か異常終了かは環境に依存するので, 初めに #include <stdlib.h> としておいて stdlib.h の中で定義されている EXIT_SUCCESS や EXIT_FAILURE を用いると どの環境でも動作するプログラムと なる. すなわち #include <stdlib.h> 正常終了のときは return EXIT_SUCCESS; 異常終了のときは return EXIT_FAILURE; */
例
#include <stdio.h> #include <math.h> /* 2次方程式の解を数値的に求めるプログラム. 判別式Dの値により異なる計算を行い, それぞれに適した形式で出力する. sqrt は平方根を求める関数. math.h の中で定義されている. gcc でコンパイルする場合は このプログラムのファイル名を a.c とすると gcc a.c -lm のように -lm オプションをつけ ライブラリ libm の中の sqrt 関数を使用する. Dは常に有効桁に起因する誤差を含むので, 条件式の中で D==0.0 のように 0.0 と等しいかどうかを調べることはできない. (D > -0.0001) && (D<0.0001) のように一定の範囲内で「0」とみなせるかどうかを 調べる必要がある. この例では 「D>+1.0e-20でなく」かつ「D<-1.0e-20でない」場合を, Dが「0」であるとした. */ int main(void) { double a, b, c, D, x1, x2; a = 1.0; b = -5.0; c = 6.0; D = b*b - 4.0*a*c; if ( D > +1.0e-20 ) { x1 = (-b+sqrt(D)) / (2.0*a); x2 = (-b-sqrt(D)) / (2.0*a); printf("x1=%g, x2=%g\n", x1, x2); } else if ( D < -1.0e-20 ) { printf("虚数解です.\n"); printf("x1 = %g + %g i, ", -b/(2.0*a), sqrt(-D)/(2.0*a)); printf("x2 = %g - %g i\n", -b/(2.0*a), sqrt(-D)/(2.0*a)); } else { printf("重解です."); printf("x=%g\n", -b/(2.0*a)); } return 0; }
数学での2乗は
と表記されるが,
C言語では x
2という表現はない.
代わりに, x*x で代用する. もしくは, pow関数を用いて,
y=pow(x, 2.0); のようにして求めることもできる.
pow関数を用いる場合は,
冒頭に #include <math.h> が必要であることに注意すること.
C言語で実数を扱う場合 実数の有効桁に注意する必要がある. 数学では 1.0/3.0 は無限小数であるが, C言語ではそのような実数を扱うことはできない. また, 実数は内部では2進数で表現されているため, 10進数で切りがよい実数でも, 2進数では無限小数になる場合がある.
例えば, 次のプログラムは, 数学的には と
は等しいが,
C言語としては等しいと判別されるであろうか.
さらに, a, b にいろいろな演算結果を代入してみるとよい.
#include <stdio.h> int main(void) { double a, b, x, y, z; x = 0.1; y = 0.01; z = 0.09; a = x; b = y+z; if ( a == b ) { puts("条件式は真です."); } else { puts("条件式は偽です."); } printf("a=%30.20e\n", a); printf("b=%30.20e\n", b); return 0; }
C言語では実数に誤差が含まれるので,
であるときすなわち
a と b の差が十分小さいとき,
と
が等しいとみなすことにする.
#include <stdio.h> int main(void) { double a, b, x, y, z, d; x = 0.1; y = 0.01; z = 0.09; a = x; b = y+z; // d = |a-b| if ( a > b ) d = a - b; else d = b - a; // |a-b| < 十分小さい数 if ( d < 1.0e-15 ) { puts("aとbは等しいとみなせる."); } else { puts("aとbは等しくない."); } printf("a=%30.20e\n", a); printf("b=%30.20e\n", b); return 0; }
double 型実数の絶対値を求める関数fabsを用いると 簡潔に表現できる. fabs関数はmath.hで定義されているので, math.h をインクルードする必要がある.
#include <stdio.h> #include <math.h> int main(void) { double a, b, x, y, z; x = 0.1; y = 0.01; z = 0.09; a = x; b = y+z; if ( fabs(a-b) < 1.0e-15 ) { puts("aとbは等しいとみなす."); } else { puts("aとbは等しくない."); } printf("a=%30.20e\n", a); printf("b=%30.20e\n", b); return 0; }
同様にaが0.1と等しいかどうかを調べるときは, 次のようになる.
#include <stdio.h> #include <math.h> int main(void) { double a, x, y; x = 0.01; y = 0.09; a = x + y; if ( fabs(a-0.1) < 1.0e-15 ) { puts("aは0.1にほぼ等しい."); } else { puts("aは0.1に等しくない."); } printf("a=%30.20e\n", a); return 0; }
(c)1999-2013 Tetsuya Makimura