
/* 1 */ /* Program 4-1 */
/* 2 */ /* 奇数,偶数 判定 */
/* 3 */ #include <stdio.h>
/* 4 */ main()
/* 5 */ {
/* 6 */ int a;
/* 7 */
/* 8 */ scanf("%d", &a);
/* 9 */ if ( a%2 == 1 )
/* 10 */ printf("%d ... odd\n", a);
/* 11 */ else
/* 12 */ printf("%d ... even\n", a);
/* 13 */ }
| 8: | 数値を整数として入力する。 |
| 9: | if文である。条件式として a%2==1 とする。これは、aを2で割った余りが1と等しければ真(0以外の数値)、等しくなければ偽(0)を値としてもつ。つまり式の値は、0または1である。 |
| 10: | 条件式の値が0以外の時に、文1つまり10:の文が実行され奇数と出力される。文の終わりに、;をつけることを忘れずに。 |
| 11: | if_else文のelseである。elseは1行に書くこと。 |
| 12: | ifの条件式の値が0の時に、12:の文が実行される。 |
ここで、if(a%2==1)をif(a%2)と変更しても同じ結果が得られる。
実行例からもわかるように、a%2が1の時には、..,8,9,10,13と実行され、a%2が0の時には、..,8,9,11,12,13と実行される。
maxを出力する。

/* 1 */ /* Program 4-2 */
/* 2 */ /* 3つの数の最大値を求める. */
/* 3 */ #include <stdio.h>
/* 4 */ main()
/* 5 */ {
/* 6 */ int a, b, c, max;
/* 7 */
/* 8 */ scanf("%d %d %d", &a, &b, &c);
/* 9 */ if (a > b)
/* 10 */ max = a;
/* 11 */ else
/* 12 */ max = b;
/* 13 */ if (c > max)
/* 14 */ max = c;
/* 15 */ printf("%d %d %d max = %d\n", a, b, c, max);
/* 16 */ }
| 8: | 3つの整数を変数a,b,cに入力する。 |
| 9−12: | aとbの値を比較し、aの値がbの値より大きい時maxにaの値を代入し、それ以外の時maxにbの値を代入する。ここで、9: の if と 11: の else を同じだけ字下げして書くことを薦める。(下記の注意を参照のこと。) |
| 13: | cとmaxの値を比較し、cの値がmaxの値より大きい時maxにcの値を代入し、それ以外の時はなにもしない。 |
| 15: | a,b,cの値を出力したあとに、最大値maxの値を出力する。 |
if ( a>b ) if( b>c ) x = c; else x = b;をどのように解釈したらよいのだろうか?
C言語の場合、elseは一番近いifに対応する。つまりこの場合、

if ( a>b ) if( b>c ) x = c; else x = b;のように対応する if と else を同じだけ字下げして書換えたほうがよい。
このように、人間の意向を明確にするために、段付け(字下げ)を行いプログラムを見やすくする。この場合、elseを1つめのifにあわせて書くと、見かけ上人間が誤った解釈をしやすく、虫(バグ)が発見しづらくなるので注意が必要である。正確に段付けを行なうことは、プログラムを見やすくするばかりでなく誤りを防ぐにも効果的である。
a>bかつb>cのときにx=cの実行を、

if ( a>b ) {
if( b>c ) x = c;
}
else x = b;
この場合、 if ( a>b ) 文1; else x = b; で、文1の中身が if ( b>c ) x = c; である。また、
if ( a>b ) {
文a;
文b;
文c;
文d;
}
else {
文v;
文w;
文x;
文y;
文z;
}
のようなプログラムの場合、a>bのとき文a〜文dを実行し、
算術演算子は、数値の+,−,×,÷などを行なうためのものである。演算結果は数値である。以下の表のようにまとめることができる。
| 優先順位 | 演算子 | 種類 | 解説 |
| 1 | + | 単項演算子 | +x |
| 1 | − | 単項演算子 | −x |
| 2 | * | 2項演算子 | x × y |
| 2 | ÷ | 2項演算子 | x ÷ y |
| 2 | % | 2項演算子 | (x÷y)の余り |
| 3 | + | 2項演算子 | x + y |
| 3 | − | 2項演算子 | x − y |
a÷b+((c%d)−(e+f))*−dの計算は、以下の順序で行なわれる。
| 優先順位 | 演算子 | 利用例 | 解説 |
| 1 | < | a<b | aの値がbの値未満 |
| 1 | <= | a<=b | aの値がbの値以下 |
| 1 | > | a>b | aの値がbの値より大 |
| 1 | >= | a>=b | aの値がbの値以上 |
| 2 | == | a==b | aとbの値が等しい |
| 2 | != | a!=b | aとbの値が等しくない |
論理演算子は&&と||で、上記算術演算子,比較演算子を使った式を組み合わせることによく用いられる。例えば、
| 優先順位 | 演算子 | 利用例 | 解説 |
| 1 | && | a && b | aかつb |
| 1 | || | a || b | aまたはb |
| 優先順位 | 演算子 |
| 1 | 算術演算子 |
| 2 | 比較演算子 |
| 3 | 論理演算子 |
1 a+b 2 1の結果>c 3 x<=y 4 2の結果 && 3の結果if文の式では、このような各種の演算子を組み合わせた式を書くこともで きる。
switch (式) { case 定数式:文1; case 定数式:文2; case 定数式:文3; : : default: 文n; }


/* 1 */ /* Program 4-3-1 */
/* 2 */ /* 数値を英単語に直す Ver. 1 */
/* 3 */ #include <stdio.h>
/* 4 */ main()
/* 5 */ {
/* 6 */ int x;
/* 7 */
/* 8 */ scanf("%d", &x);
/* 9 */ switch ( x ) {
/* 10 */ case 1: printf("One\n"); break;
/* 11 */ case 2: printf("Two\n"); break;
/* 12 */ case 3: printf("Three\n"); break;
/* 13 */ default: printf("otherwise\n"); break;
/* 14 */ }
/* 15 */ }
| 8: | 数値の入力。xに整数として読み込む。 |
| 9〜14: | switch−case文である。xの値によって実行文が変わる。この場合、x=1のとき10:を、x=2のとき11:を、x=3のとき12:を実行する。それぞれ printf で英単語を出力したのち break 文によってswitch−cace文をぬける。つまり14:へ制御が移る(実行がとぶ)。 もし、10:で break 文をなくすと、x=1のときには One と Two が出力される。これは break 文がないために制御が次の文(11:)に移ったため、 Two も出力されることになる。 |
| 13: | default: は、caseで該当するものがないときに実行したい文を記述しておける。この場合、x=1,2,3のいずれでもないときに otherwise と出力される。 |
例 入力:2 出力:two three four five 入力:4 出力:four file 入力:7 出力:otherwiseswitch−case文は、if文の拡張であることを前にも説明した が、以下では例4−3をif文を使って実現してみよう。

/* 1 */ /* Program 4-3-2 */
/* 2 */ /* 数値を英単語に直す Ver.2 */
/* 3 */ #include <stdio.h>
/* 4 */ main()
/* 5 */ {
/* 6 */ int x;
/* 7 */
/* 8 */ scanf("%d", &x);
/* 9 */ if (x == 1)
/* 10 */ printf("One\n");
/* 11 */ else if (x == 2)
/* 12 */ printf("Two\n");
/* 13 */ else if (x == 3)
/* 14 */ printf("Three\n");
/* 15 */ else
/* 16 */ printf("Otherwise\n");
/* 17 */ }
| 9−16: | プログラム4−3−1の 9:-14: で行なっていることを if-else 文を組み合わせて実現している。この例のプログラムは if 文が3重になっていて、else がどのif と対応しているのかがわかりづらいのが、難点である。 |

/* 1 */ /* Program 4-3-3 */
/* 2 */ /* 数値を英単語に直す Ver. 3 */
/* 3 */ #include <stdio.h>
/* 4 */ main()
/* 5 */ {
/* 6 */ int x;
/* 7 */
/* 8 */ scanf("%d", &x);
/* 9 */ if (x == 1)
/* 10 */ printf("One\n");
/* 11 */ if (x == 2)
/* 12 */ printf("Two\n");
/* 13 */ if (x == 3)
/* 14 */ printf("Three\n");
/* 15 */ }
| 9−14: | この場合、3つの if 文を用いて実行している。break のような文はなく、すべての if 文で判定され、x の値が該当する時のみ英文が出力される。このように if 文のみを使って実現した場合、x=1,2,3 のでれでもない時には、otherwise を出力することが難しくなる。14: と 15: の間に
if (!( x==1 || x==2 || x=3 ))
printf("otherwise\n");
を挿入すれば実現できるが、あまりエレガントではない。 |
ここで、もう少し実際的な例を考えよう。
解の公式: D=b^2-4ac としたとき D=0 のとき x = -b/2a D>0 のとき x = (-b+ ��D )/2a , (-b- ��D )/2a D<0 のとき x = (-b+ ��(-D) i)/2a , (-b- ��(-D) i)/2a ただし、a,b≠0 とする。

/* 1 */ /* Program 4-4-1 */
/* 2 */ /* 2次方程式を解く Ver.1 */
/* 3 */ #include <stdio.h>
/* 4 */ #include <math.h>
/* 5 */
/* 6 */ main()
/* 7 */ {
/* 8 */ float a, b, c, d, x1, x2;
/* 9 */
/* 10 */ scanf("%f %f %f", &a, &b, &c);
/* 11 */
/* 12 */ d = b * b - 4 * a * c;
/* 13 */ if ( d > 0.0 )
/* 14 */ {
/* 15 */ x1 = ( -b + sqrt(d)) / ( 2 * a);
/* 16 */ x2 = ( -b - sqrt(d)) / ( 2 * a);
/* 17 */ printf("%f, %f\n", x1, x2);
/* 18 */ }
/* 19 */ else if ( d < 0.0 )
/* 20 */ {
/* 21 */ x1 = -b / ( 2 * a );
/* 22 */ x2 = sqrt(-d) / ( 2 * a );
/* 23 */ printf("%f+%fi, %f-%fi\n", x1, x2, x1, x2);
/* 24 */ }
/* 25 */ else
/* 26 */ {
/* 27 */ x1 = -b / ( 2 * a );
/* 28 */ printf("%f\n", x1);
/* 29 */ }
/* 30 */ }
| 4: | 計算の中で �� (ルート:2乗根) の計算をするために、数学計算用の関数ライブラリを利用する宣言をする。 |
| 10: | 方程式のa,b,cを実数型で入力する。 |
| 12: | 判別式 D の計算をする。 |
| 13−18: | D>0の時の計算を行なう。判別式の値が正であるので、2つの異なる解を持つため、それぞれを x1, x2 として公式にあてはめ計算している。ここで、sqrt は 4: で宣言した math.h ライブラリ内の関数で2乗根をもとめるための関数である。sqrt を用いるために 4: の宣言が必要である。 |
| 19−24: | D<0のときは異なる虚数解を持つため、実部を x1, 虚部を X2 として計算し、出力のときに虚数部の後に "i" を出力するようにしている。 |
| 25−29: | D=0のときは、重解をもつためそれを x1 として、計算している。 |
/* 1 */ /* Program 4-4-2 */
/* 2 */ /* 2次方程式を解く Ver.2 */
/* 3 */ #include <stdio.h>
/* 4 */ #include <math.h>
/* 5 */
/* 6 */ main()
/* 7 */ {
/* 8 */ float a, b, c, d, x1, x2;
/* 9 */ int sw;
/* 10 */
/* 11 */ scanf("%f %f %f", &a, &b, &c);
/* 12 */
/* 13 */ d = b * b - 4 * a * c;
/* 14 */ if ( d > 0.0 )
/* 15 */ sw = 1;
/* 16 */ else if ( d < 0.0 )
/* 17 */ sw = 2;
/* 18 */ else
/* 19 */ sw = 3;
/* 20 */
/* 21 */ switch (sw) {
/* 22 */ case 1:
/* 23 */ x1 = ( -b + sqrt(d)) / ( 2 * a);
/* 24 */ x2 = ( -b - sqrt(d)) / ( 2 * a);
/* 25 */ printf("%f, %f\n", x1, x2);
/* 26 */ break;
/* 27 */ case 2:
/* 28 */ x1 = -b / ( 2 * a );
/* 29 */ x2 = sqrt(-d) / ( 2 * a);
/* 30 */ printf("%f+%fi, %f-%fi\n", x1, x2, x1, x2);
/* 31 */ break;
/* 32 */ case 3:
/* 33 */ x1 = -b / ( 2 * a);
/* 34 */ printf("%f\n", x1);
/* 35 */ break;
/* 36 */ }
/* 37 */ }
souwa = 1 + 2 + 3 + ・・・・ + nこれをアルゴリズムで考える。
1 souwa を0に初期化する 2 i を1に初期化する 3 souwa に i の値を加える 4 i の値に1を加える 5 i の値が n より小さい時はステップ3へ、それ以外の時はステップ6へ 6 souwa を出力

while文は条件判定が文頭にあり、繰り返しの本体がそれに続く。一般形式は次のようである。
条件式の初期化; while( 繰り返しの条件式 ){ 文1; : : 文n; }
繰り返しの条件式の値が真の間は、文を繰り返し実行する。流れ図からも見られるように繰り返しの実行前に、条件式を評価している点がwhile文の特徴である。条件式の値によっては、文1−文nが1度も実行されないこともある。また、通常while文のまえに、条件式の初期化文が置かれている。{文1−文n}が1文の時には、while( )のあとに{ }を省いて文を書いてもよい。
それでは、while文を使って例4−5をプログラムしてみよう。
/* 1 */ /* Program 4-5-1 */
/* 2 */ /* 1からnまでの合計を求める Ver 1 */
/* 3 */ #include <stdio.h>
/* 4 */ main()
/* 5 */ {
/* 6 */ int souwa,i, n;
/* 7 */
/* 8 */ scanf("%d", &n);
/* 9 */ souwa = 0;
/* 10 */ i = 1;
/* 11 */ while(i <= n)
/* 12 */ {
/* 13 */ souwa = souwa + i;
/* 14 */ i = i + 1;
/* 15 */ }
/* 16 */ printf("%d\n", souwa);
/* 17 */ }
| 9: | 総和を求めるための変数 souwa を0に初期化する。これは、 13: で souwa = souwa + i として利用するためである。 |
| 10: | while文の条件の初期化文である。 |
| 11: | while文の始まりで、12:から15:が繰り返しの本体である。繰り返しの条件として i <= n を満たしているあいだ繰り返される。 |
| 13: | 総和にiの値が繰り返し加えられるため、最終的には1からiの総和が求まる。 |
do−while文は、条件判定が繰り返し文の後ろに付く点でwhile文とは、異なる。一般形式と制御の流れは以下のようである。
do{ 文1; : : 文n; }while( 繰り返しの条件式 )
文1−文nが実行された後に繰り返しの条件式を評価し、その値が真なら ば文1−文nが再び実行され、式の値が偽ならば繰り返しが終了する。つま り、条件式の値が真の間は、文1−文nが繰り返し実行される。またdo_ while文では、必ず1回は文1−文nが実行されることに注意して欲し い。
while文の時にあった条件式の初期化が、do_while文に入る 前に必ずしも必要ではない。それは、文1−文nでなんらかの条件判定式に かかわる演算を行なう可能性があるからである。逆に、while文は、先 頭に条件判定があるために、条件式の初期化が前もって必要なのである。
プログラム4−5−2にdo_whileの例を示す。
/* 1 */ /* Program 4-5-2 */
/* 2 */ /* 1からnまでの合計を求める Ver 2 */
/* 3 */ #include <stdio.h>
/* 4 */ main()
/* 5 */ {
/* 6 */ int souwa,i, n;
/* 7 */
/* 8 */ scanf("%d", &n);
/* 9 */ souwa = 0;
/* 10 */ i = 1;
/* 11 */ do{
/* 12 */ souwa = souwa + i;
/* 13 */ i = i + 1;
/* 14 */ }while( i <= n);
/* 15 */ printf("%d\n", souwa);
/* 16 */ }
| 11: | do_whileの始まりである。繰り返しの本体が12:−13:である。 |
| 14: | 繰り返しの終了条件で、 i <= n のあいだ繰り返される。 |
式1; while ( 式2 ){ 文; 式3; }は,for文で
for( 式1; 式2; 式3 ){ 文; }のように書ける。ここでfor文の文は複文( 複数の文を { } を使って表現したもの )でもよい。
制御の流れはwhile文と同じである。for文は、まず式1で条件の初期化をする。式2で繰り返しの条件判定を行い、その値が真の時に文を実行し、偽の時にfor文を終わる。文が実行された後に式3を実行し、その後 式2を評価する。これを式2の値が真の間繰り返し行なわれる。つまり、式1を最初に1度実行し、式2の条件が真の間文と式3を実行することになる。式1−式3はそれぞれ、1つの式でなくてもよい。複数の式を書きたいときには、,で区切って複数の式を並べてもよい。
プログラム4−5−3にfor文を使ったプログラムを示す。
/* 1 */ /* Program 4-5-3 */
/* 2 */ /* 1からnまでの合計を求める Ver 3 */
/* 3 */ #include <stdio.h>
/* 4 */ main()
/* 5 */ {
/* 6 */ int souwa,i, n;
/* 7 */
/* 8 */ scanf("%d", &n);
/* 9 */ souwa = 0;
/* 10 */ for (i = 1; i <= n; i = i + 1)
/* 11 */ souwa = souwa + i;
/* 12 */ printf("%d\n", souwa);
/* 13 */ }
| 10: | for文のヘッダである。通常for文は、式1(i=1)が繰り返し文の条件 |
| 11: | 繰り返しの本体である。 |
次の例を考えよう。
入力:5 出力:***** **** *** ** * |
初めの行にn個の*を出力し改行する。 次の行にn−1個の*を出力し改行する。 次の行にn−2個の*を出力し改行する。 : : 最後に1個の*を出力し改行する。 |
1 n の入力 2 i を n , n-1, n-2, ..., 1 まで3,4を繰り返す(出力の行数のカウント) 3 *を i 個出力する 4 改行する 5 終わり |
3.1 j を 1, 2, ... ,i まで 3.2を繰り返す 3.2 *を1つ出力する |
よって、繰り返しが2重になっていることがわかるであろう。
以下3種類のプログラムをあげ、比較してみよう。
/* 1 */ /* Program 4-6-1 */
/* 2 */ /* 直角二等辺三角形を表示する Ver 1 */
/* 3 */ #include <stdio.h>
/* 4 */ main()
/* 5 */ {
/* 6 */ int i, j, n;
/* 7 */
/* 8 */ scanf("%d", &n);
/* 9 */ i = n;
/* 10 */ while(i > 0)
/* 11 */ {
/* 12 */ j = 1;
/* 13 */ while(j <= i)
/* 14 */ {
/* 15 */ printf("*");
/* 16 */ j = j + 1;
/* 17 */ }
/* 18 */ printf("\n");
/* 19 */ i = i - 1;
/* 20 */ }
/* 21 */ }
/* 1 */ /* Program 4-6-2 */
/* 2 */ /* 直角二等辺三角形を表示する Ver 2 */
/* 3 */ #include <stdio.h>
/* 4 */ main()
/* 5 */ {
/* 6 */ int i, j, n;
/* 7 */
/* 8 */ scanf("%d", &n);
/* 9 */ i = n;
/* 10 */ do{
/* 11 */ j = 1;
/* 12 */ do{
/* 13 */ printf("*");
/* 14 */ j = j + 1;
/* 15 */ }while(j <= i);
/* 16 */ printf("\n");
/* 17 */ i = i - 1;
/* 18 */ }while(i > 0);
/* 19 */ }
/* 1 */ /* Program 4-6-3 */
/* 2 */ /* 直角二等辺三角形を表示する Ver 3 */
/* 3 */ #include <stdio.h>
/* 4 */ main()
/* 5 */ {
/* 6 */ int i, j, n;
/* 7 */
/* 8 */ scanf("%d", &n);
/* 9 */ for(i = n; i > 0; i = i -1)
/* 10 */ {
/* 11 */ for(j = 1; j <= i; j = j + 1)
/* 12 */ printf("*");
/* 13 */ printf("\n");
/* 14 */ }
/* 15 */ }
入力:4 出力: * * * * * *******
while(i > 0)
{
j = 1;
:
}
のように while( ) のあとに改行して { をつけるスタイルと、参考書な
どによっては
while(i > 0) {
j = 1;
:
}
のように while( ) のすぐあとに { をつけるスタイルがある。カーニハ
ン著の「プログラミング言語C」や各種の参考文献では後者のスタイルを採
用しているものが多いが、ここでは前者のスタイルに統一することとする。
とちらが良い,悪いというこはないのだが、著者の考えでは{ と }の位
置が対応づいているため分かりやすいのではないかと考えている。