第十回 6 月 23 日

課題の補足

printf() 文の中でも式は評価される。従って、 前置演算(++,--)は printf() 文が実行される前に評価され、 後置演算子は printf() 文が実行された後に評価される。

課題の補足:ビット演算子

ハンドアウトでは取り上げなかったが、その他の演算子としてビット演算子がある。ビット演算子とはビット単位でデータ操作をするものであり、オペランドは整数に限られる。ビット演算子には以下のものがある。

ビット演算子
演算子意味
&ビットごとの論理積
|ビットごとの論理和
^ビットごとの排他的論理和
~ビットごとの反転(1 の補数)

この他、先に挙げた >>,<< もビット演算子である。 ビット演算子のサンプルプログラムを以下に示す。 bit_operator.cbit_operator2.c。 ビットごとの排他的論理和 ^ は、暗号回路に用いられる。ある ビット列を鍵となるビット列との排他的論理和で暗号化した場合、もう一度同 じ鍵との排他的論理和を用いると元のビット列が復号化される。

秀逸な解答

課題 3 の排他的論理和を求める問題で、


x = ( p + q ) % 2;

及び


x = ( p - q ) * ( p - q );

の二つは秀逸であった。前者は両変数の和を 2 で割った余りが 1 である場合真となり他は偽となるため、排他的論理和の演算になっている。後者は、両変数の差の 2 乗が 1 である場合に真であるので、 (0,0), (1,1) の場合には 0 * 0 となって偽になる。一方、(0,1), (1,0) の場合には 1 であるから真となる。

4.8 キャスト演算子

変数の型を変換する演算子をキャスト演算子という。用法は
(型) 式
となる。例えば int 型の変数を double 型に変換する場合などである。例えば 例 4.11 cast.c のように用いる。

5 制御文

5.1 構造化プログラミング

順次、選択、繰り返し、の 3 つの要素だけからなっているプログラミングメソッドを構造化プログラミングという。この 3 つの要素さえあれば後述する goto 文は不要である。

5.2選択文

5.2.1 if ()

if 文は、


if (条件式)
  文;

のように用いる。条件式が真(0でない)場合、文が実行される。条件式が真である場合、 実行される文が複数ある場合は、それらを中括弧({})で括る。例えば、


if (total > 0) {
  ++count;
  printf("合計値は正です。\n");
}

などのように用いる。 通常、{}で囲んだ文は読みやすくするためインデントする。 インデントが適切でないと可読性が下がるばかりでなく、バグの原因となる。 Emacs の C モード(拡張子が .c のファイルを編集している時)では、オートインデンテーションが オンとなり、2 文字分の空白が挿入される。

5.2.2 if-else

if 文は else を伴って、2 分岐型の処理をおこなわせることができる。書式は、


if (条件式)
  文;
else
  文;

である。例えば、


if (year % 4 == 0)
  printf("Olympic game will be held!\n");
else
  printf("Olympic game won't be held\n");

などとする。ここで次のような、閏年を判定するプログラムを考えてみよう(閏年は西暦年が 4 で割り切れる年であり、ただし 100 で割り切れる年は平年であり、ただし 400 で割り切れる年は閏年である)。


if (year % 4 == 0)
    if ( year % 100 == 0 )
        if ( year % 400 == 0 )
        printf("Leap year\n");
        else
           printf("Not leap year\n");
    else
        printf("Leap year\n");
 else
    printf("Not leap year\n");

このプログラムは if が 3 つ、else が 3 つ出てくる。 どの if が、どの else に対応しているのかわかりずらい。 更に、閏年の時だけ count という変数を増加させるコードを追加すること を考えると、このコードは破綻を来す。


/* 間違ったプログラム */
if (year % 4 == 0)
    if ( year % 100 == 0 )
        if ( year % 400 == 0 )
        printf("Leap year\n");
           count++;
        else
           printf("Not leap year\n");
    else
        printf("Leap year\n");
        count++;
 else
    printf("Not leap year\n");

このコードは正しく動作しない。正しく動作させるためにはカッコを用いて、


if (year % 4 == 0) {
    if ( year % 100 == 0 ) {
        if ( year % 400 == 0 ) {
        printf("Leap year\n");
           count++;
        } else {
           printf("Not leap year\n");
        }
    } else {
        printf("Leap year\n");
        count++;
    } 
} else {
    printf("Not leap year\n");
}

と、しなければならない。プログラムを美しく書く習慣は、保守性を高め、思 わぬバグを未然に防ぐ効果を持っている。正しくインデントして美しくコード を書く習慣を身に付けなければならない。

5.2.3 switch

switch 文は if, else 文を幾つも重ねた文と同じ役割をする 多重分岐文である。


switch(式) {
    case 定数式1:
        文;
        ...
        break;
    case 定数式2:
        文;
        ...
        /* break が無ければ下の文が実行される */

    case 定数式3:
        文;
        ...
        break;
    deafult :
        文;
        ...
        break;
}

なお、各 case の最後につける break 文は必須ではない。 break 文は制御を次の処理に移すための命令であって、なければ直下 の文が実行されることになる。
switch.c


戻る

Shin-ichi ASAKAWA
asakawa@ieee.org