プログラミング講座トップ ひつじTOWN デジタルシープラーニング

ひつじのC言語入門への道 第8回 くせ者の「条件式」

プログラムは、コンピュータに対して処理の手続きを教えるものですが、1つずつ順に行うという単純な処理は現実にはありません。条件分岐や繰り返し等の処理を定義するための構文が用意されています。この回では、条件分岐の構文であるif文を取り上げて、そのなかで使われる条件式を説明したいと思います。
りんごを買いなさい
という単純な命令から、
もし、お金をもっているなら、りんごを買いなさい
あるいは、もうちょっと複雑に、
もし、お金をもっているなら、りんごを買いなさい
そうでなければ(お金をもっていなければ)、お母さんにお金を貰ってきなさい
このように、ある処理(りんごを買う)を行うにあたって、前提条件が必要だったり、条件によって、次に行う処理の内容を変えたり、というのはよくあることです。このような場合にif文の構文を利用します。
構文というと英語の構文を思い出す人もいるかもしれませんが、プログラムの構文は、幸いにわずかで、その代表的なものは条件分岐と繰り返し処理です。BasicやFortran等には、さらに、ジャンプ文(GO文)があります。

if文の構文は次のようになっています。
if (条件式) 実行文。

または、

if (条件式) 実行文1。
else 実行文2。
りんごの買い物の条件を当てはめると次のようになります。
if (お金をもっている?) りんごを買いなさい

または、

if(お金をもっている?) りんごを買いなさい
else お母さんからお金を貰ってきなさい
さて、本論のくせ物「条件式」ですが、この条件式は、「真(true)」か「偽(false)」の判定をします。真か偽かというのは具体的には次のような定義になっています。 
「真である」ということは条件式の結果が0以外の時。
偽は真の反対なので、
「真である」ということは条件式の結果が0の時。
ということになります。

りんごの買い物を少しプログラムチックに書き直してみます。
OKANE = 1000;
if (OKANE > 0) りんごを買いなさい
直感的に、「お金があれば、りんごを買う」ということは理解出来るかと思います。そこで、上記の定義から判断すると、
(OKANE > 0)
この条件式は、「OKANEが0より大きいならば」と理解することが出来るので、また、その結果は「真」であるので、りんごを買うことが出来ます。これは直感的にわかりやすいですね。
「真である」ということは条件式の結果が0以外の時。
「偽である」ということは条件式の結果が0の時。
という理屈を理解しているならば、このプログラムは次のように書くことが出来ます。
OKANE = 1000;
if (OKANE) りんごを買いなさい
OKANEの値は1000なので、「0以外」つまり「真」ということなるので、りんごを買うことが出来ます。OKANE > 0 と記述した方が、「OKANEが0より大きい場合には」と読むことが出来るので、プログラムの可読性は良いですね。
一方で OKANE だけの場合は、コンピュータとしては「OKANE > 0」という判断する処理を省略出来るので、実行速度の面では効率が良い、ということになります。

C言語の場合、歴史的に、プログラムの実行速度やプログラムサイズを小さくして、実行効率を上げることを優先することが多いので、後者の方で書く人が多いようです。
筆者は、原則プログラムの可読性(読み易さ)を第一に優先すべきだと考えます。
でも、他の人が、自分が作ったプログラムを見る可能性がある場合には、ミエを張って、出来るだけ短く、実行効率の良いように作ります^^; しようがないですね^^;
そうでなければ、後に見直すときに、わかりやすいように可読性を優先します。

さて、話を戻して、

条件式というのは、大雑把に言って次の2つのケースがあります。
if(値)
If(式)
値の場合は、その値が「0」か「0で無い」か、で判断します。式の場合は、式の結果が「0」か「0で無い」か、で判断します。

「条件式が正しいか、正しくないかを判定する。」というように一般的に理解しますが、正しい云々はあまり意識しない方が良いようです。「正しい」という定義にしてしまうと、どうしても人間の常識的な考えが入ってくるので、プログラムも理解を妨げることがあるように思います。

さて、次のプログラムを見てください。
strcmpという関数は、2つの文字が等しいかどうかを判定する関数で、等しい場合には結果が「0」となります。等しくない場合はどういう値になるかですが、文字コードの引き算をしています。これはまだ覚える必要はありません。

この関数名ですが、string compareからネーミングされていると思われます。プログラム言語の関数名は、もともとの英語での意味から、母音を省略して並べて作られることが多いです。これはプログラム言語に限らず、一般的にもよく使われる短縮形の作り方の一つですね。自身で関数を作る際にもこのルールに従うと他の人にもわかりやすい名前になります。
話を戻します。
if (strcmp(moji1,moji2) == 0)
printf(“2つの文字は同じ文字です”);
上記に式はstrcmpの結果が0と等しいかどうかをif文で判定しています。
「==」は、比較演算子と呼ばれているもので、等しいかどうかを判定する記号です。数学でいうところの「=」と同じです。ところが「=」は代入文として既に利用しているので、比較する記号としては「==」を使います。
  次のプログラムを見てください。比較することを省きました。
if (strcmp(moji1,moji2))
printf(“2つの文字は同じ文字です”);
strcmpは等しいと0という結果を返す関数なので、判定後は、if(0) つまり、if(偽)となるので上記は間違った処理になります。
そこで、「!」という記号を使って、
if (!strcmp(moji1,moji2))
printf(“2つの文字は同じ文字です”);
と書くことが出来ます。
「!」は、「真を偽」」、「偽を真」に値を反転させる記号です。

  条件式のなかで関数を利用する際には、その関数の戻り値(return value)をよく調べないといけません。
条件式のまとめとして、
条件(式)の結果が0以外だと「真である」。つまり条件が成立する。
条件(式)の結果が0だと「偽」である。つまり成立しない。
whike文で次のように書いていることを見ることがあります。
While(1) {
xxxxx;
}
これは、条件の結果が常に1なので、つまり常に真であるため、いつまでもxxxxxが実行されます。いわゆる無限ループですね。この1に意味があるのではなくて、0以外なら何でもいいのですが、-9や1000とかするよりは単純に1とした方が見た目に美しい?ので、そうしているのでしょう。

筆者個人は、真であるケースがたくさんあるのに対して、偽になるのが1通り(0のとき)である、というのがなんとなく腑に落ちません。0の時が真であるとつい勘違いしてしまいます。 なので、繰り返しになりますが、「条件式が正しいか、正しくないかを判定する。」というように一般的に理解しますが、正しい云々はあまり意識しない方が良いようです。

<筆者用メモ>strcmpの仕様

strcmpの仕様は次のようになっています。
【書式】
#include <string.h>
int  strcmp(const  char  *s1,  const  char  *s2);

【説明】
文字列s1と文字列s2を比較します。

【引数】
const char *s1 : 比較文字列1
const char *s2 : 比較文字列2

【戻り値】
s1 = s2で 0 を返す。それ以外はs1の文字コードからs2の文字コードを引いた値を返す。
ところで
int  strcmp(const  char  *s1,  const  char  *s2);
この意味を初心者が理解するのは不可能。どこかの回で説明したいと思います。

<筆者用メモ>論理演算子

内容
a & ba と b の論理積(AND)
a | ba と b の論理和(OR)
a ^ b排他的論理和(XOR:exclusive OR)
!aa の否定(NOT)
a && ba と b の論理積(ショートカット演算子)
a || ba と b の論理和(ショートカット演算子)
論理演算子は true(真)と false(偽)の演算結果が事前に定められており、「真理値表」とも呼びます。
●真理値表
ab
a&ba|ba^b!a
この論理演算は、値に対しても適用することが出来ます。値の場合は以下のようになります。
●真理値表(1と0で置き換えた場合)
ab
00
01
10
11
a&ba|ba^b!a
0001
0111
0110
1100


[←] 第7回へ | [↑] プログラミング講座トップへ