プログラムの流れの制御は, 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