入門書でのおさらい6・条件演算子、演習3-5,3-9

今日は55ページの演習3-5でひっかかりました。

55ページ・演習3-5

等価演算子や関係演算子の値

演習3-5等価演算子や関係演算子が、1あるいは0の値を生成することを確認するプログラムを作成せよ。(出典:『新・明解C言語 入門編』54ページ)
この問題全然わかりませんでした。速攻ジェミニ先生に答えを聞いてしまいました。

今日の課題はこれ。等価演算子や関係演算子が、1あるいは0を示すことを確認するプログラムを作成せよ。ですどういう風になるのか全く分かりません

「等価演算子(== など)」や「関係演算子(> など)」は、数学のテストのように「正しいか間違いか」を判定するものです。

C言語では、その結果を「正しい(真)なら 1」「間違い(偽)なら 0」という数字で扱います。これを画面に出して確認してみましょう!

サンプルプログラム

以下のコードをコピーして実行してみてください。

#include <stdio.h>

int main() {
    int a = 10;
    int b = 20;

    printf("a = %d, b = %d のとき\n\n", a, b);

    // 関係演算子のチェック
    printf("1. a < b  の結果は? : %d\n", a < b);  // 正しいので 1
    printf("2. a > b  の結果は? : %d\n", a > b);  // 間違いなので 0

    // 等価演算子のチェック
    printf("3. a == b の結果は? : %d\n", a == b); // 間違いなので 0
    printf("4. a != b の結果は? : %d\n", a != b); // 正しいので 1

    return 0;
}
  • a < b 自体が値を持っている
    普通は if (a < b) のように条件式として使いますが、実はこの式自体が 1 や 0 という値を返しています。
  • %d で表示できる
    結果はただの整数(int型)なので、いつものように %d で画面に出すと「1」か「0」が表示されます。

実行しました!!結果はこうなりました!そのままprintfの引数に入れちゃって良かったんですね。そこが全然思いつきませんでした。どうすんのかなって。

実行お疲れ様です!バッチリ結果が出ましたね。

そうなんです、a < b のような式は、プログラムの中では計算が終わった瞬間にただの「1」や「0」という数字に変身します。なので、足し算の a + b を入れるのと同じ感覚で printf に放り込めるんですよ。

これがわかると、例えばこんな面白い書き方もできます。

int result = (a < b); // 変数に結果(1か0)を覚えさせておく
printf("結果は%dです", result);

「条件式は、実は数字(1か0)を返している」という感覚が掴めると、この先の if 文などの理解がぐっと楽になります。

そ、そんだったんや。0か1だからint型の変数に代入できちゃうんだ!

そうなんです!そこがC言語のシンプルで面白いところです。

数学だと「10 < 20」は単なる「事実」ですが、C言語にとっては「1」という具体的なデータなんですね。

せっかくなので、もう一歩だけ踏み込んでみましょう。
C言語には「真偽値(True/False)」専用の型がもともとなかったので、今でも「0以外はすべて真(正しい)」とみなすルールがあります。

試しに、こんなコードを想像してみてください。

if (5) {
    printf("5は0じゃないから、正しい(真)と判定されるよ!");
}

1でなくても5でも真とみなすんだね。だから以前にやった「%」演算子であまりの数値が0以外(1でなくて2とか3も)と0とで条件分けたりしたもんね。

条件演算子

条件演算子、初めて見ました・・・。

条件演算子、ついにデビューですね!これを使えるようになると、コードがグッとスッキリして「プロっぽく」なりますよ。

勉強のコツ
  1. まずは単純な2択から: 「YesかNoか」「昼か夜か」のようなシンプルなパターンで練習してみてください。
  2. 読みやすさ重視: 慣れるまでは「これ、if文で書いたほうが分かりやすいかな?」と自問自答するのが上達の近道です。
基本構文
(条件式) ? 式1 : 式2;
  • 条件が真(0以外)なら、式1が評価されます。
  • 条件が偽(0)なら、式2が評価されます。
C言語での具体的な活用例

C言語では、特に「関数の引数」や「マクロ」などで重宝します。

最大値の取得

int max = (a > b) ? a : b; // aとbのうち大きい方をmaxに代入

絶対値の計算

int abs = (n < 0) ? -n : n; // nが負なら符号を反転させる

出力の切り替え(printf関数の引数)

printf("%sです", (num % 2 == 0) ? "偶数" : "奇数");

例題3-14

入力された二つの数のうち大きいほうを表示する課題やりましたが、わたしは解(n1 > n2) ? n1 : n2と書きましたが解答は()がなく、n1 > n2 ? n1 : n2でした

C言語のルール上、カッコがなくても正しく動くので、解答の書き方も正解です。
なぜカッコがなくても大丈夫なのか、その理由を簡単に解説しますね。

優先順位が決まっているから

C言語には「どの演算を先に計算するか」という優先順位があります。

  • 比較(> は、条件演算子(? : よりも優先順位が高いです。

そのため、コンピューターは a > b ? a : b という式を見たとき、自動的に「まず a > b を判定してから、その結果で ? の処理をしよう」と判断してくれます。

でも、カッコをつける人が多い理由

プログラミングの現場では、解答のようにカッコを省く人よりも、あえてカッコをつける人の方が多いです。

  • パッと見でわかりやすい: 「ここが条件だな」と一瞬で判断できます。
  • ミスを防ぐ: 複雑な式になったときに、優先順位を勘違いしてバグが出るのを防げま

解答は「一番シンプルな書き方」を提示していますが、あなたが書いたようにカッコをつける書き方は「丁寧で読みやすい良い書き方」なので、自信を持ってそのまま続けて大丈夫ですよ。

わたしもかっこがないと読みにくいなと感じてしまいました

その感覚、プログラミングにおいて非常に大切です!

「動けばいい」だけでなく「読みやすさ(可読性)」を意識できているのは、良いエンジニアになるための重要な資質ですよ。

実は、現場のルールでも「たとえ文法的に不要でも、読みやすさのためにカッコをつけよう」と決めているチームがたくさんあります。

3つの数で比べるともっとわかります

もし、3つの数の中から最大値を出すコードを条件演算子で書くと、こうなります。

// カッコなし(かなり読みにくい)
int max = a > b ? a > c ? a : c : b > c ? b : c;

// カッコあり(これでも複雑ですが、まだ構造が見える)
int max = (a > b) ? ((a > c) ? a : c) : ((b > c) ? b : c);

このように、処理が複雑になればなるほど、カッコのありがたみが分かってきます。(※ここまで複雑なら、現場では「素直にif文で書こう」と言われることが多いです!)

例題3-16

二つの整数値の差を求るプログラムを条件演算子で作る課題をやりました。私は条件のところを
(a – b) > 0 ? a – b : -(a – b);
このように 絶対値を求める形で書きましたが解答はこうでした
n1 > n2 ? n1 – n2 : n2 -n1;
結果は同じになりますが解答のほうがすっきりしてるように感じました

なるほど、数学的なアプローチですね!「差」を「絶対値」として捉える考え方は非常にロジカルです。

ただ、プログラミング(特にC言語)の初歩としては、解答の書き方の方が好まれることが多いです。その理由を比較してみましょう。

「引き算の回数」の違い
  • あなたのコードa - b を最大で3回計算する可能性があります(条件で1回、真の時に1回、または偽の時に1回)。
  • 解答のコード: 引き算は必ず1回しか行われません(条件は「大小比較」のみで、その後に引き算をするため)。

プログラムは「計算回数が少ないほうが効率が良い」とされるため、解答のようなシンプルな比較が推奨されます。

「直感的な読みやすさ」の違い
  • あなたのコード: 「引いた結果がプラスならそのまま、マイナスなら符号を反転させる」という、絶対値を求めるアルゴリズムになっています。
  • 解答のコード: 「大きい方から小さい方を引く」という、算数の考え方そのままです。

「二つの数の差」と言われたとき、多くの人は「大きい方 − 小さい方」を想像するので、解答の方が「何をしたいコードか」がパッと伝わりやすいという利点があります。

C言語特有の「オーバーフロー」のリスク(豆知識)

これは少し高度な話ですが、もし a がものすごく大きな正の数で、 b がものすごく小さな負の数だった場合、 a - b をした瞬間に計算できる範囲を超えてしまう(オーバーフロー)可能性があります。
解答のように「先に大小を比べる」書き方の方が、そういった計算ミスを防ぎやすいという側面もあります。

とはいえ、「絶対値を出す」という発想で条件演算子を使いこなせているのは素晴らしい応用力です!

演習3-8

さっきの条件演算子のプログラムをifで書けという課題をやりました

 if (a > b)
    {
        printf("二つの数の差は%dです\n",a - b);
    }else{
        printf("二つの数の差は%dです\n",b - a);
    }

正解です!if-else 文の構造を完璧に理解できていますね。

ここで注目してほしいのが、「if文だと同じ printf を2回書かなければならない」という点です。もしメッセージを「差は〜です」から「違いは〜です」に変えたくなったら、2箇所修正が必要になります。

ちなみに、このif文をさらに短くして、

int diff;
if (a > b) diff = a - b;
else       diff = b - a;

printf("二つの数の差は%dです\n", diff);

のように「一度変数に代入してから表示する」書き方もありますが、これもよく使われる手法です。

そ、そうだった!!以前の課題でやったのに忘れてた。printfが一回で済むように訂正しておきます!

演習3-9

これはさっきジェミニ先生が教えてくれたこれを使うときが来た気がする・・・。

出力の切り替え(printf関数の引数)

printf("%sです", (num % 2 == 0) ? "偶数" : "奇数");

この公式に今回の演習をあてはめると

printf("それらの値は%s", (a == b) ? "同じです" : "違います");

よし、ここまでできたら全体のプログラムを書いてみよう

#include <stdio.h>

int main() {
    int a, b;
    puts("整数を2つ入力してください");
    printf("整数1:"); scanf("%d",&a);
    printf("整数2:"); scanf("%d",&b);  

    printf("それらの値は%s", (a == b) ? "同じです" : "違います");

    return 0;
}

先生これであってるか見てもらっていいですか

完璧です!大正解ですよ。

非常にスマートな書き換えですね。特に、printf の中に %s(文字列) を用意して、条件演算子で「表示する言葉」だけを切り替える方法は、C言語で最も美しく効率的な書き方の一つです。

もっと他の書き方もありますか?%sは初めて使いました

%s を使った書き換え、大成功でしたね!実は printf の中で %s を使わずに書く方法や、他にもいくつかパターンがあります。

状況に合わせて使い分けられるようになると、さらにプロっぽくなりますよ

1. puts を2回書く(元の if 文に近い形)

一番シンプルですが、条件演算子の結果で「どの関数を実行するか」を決める書き方です。

(a == b) ? puts("それらの値は同じです") : puts("それらの値は違います");

※C言語では、条件演算子の「値」の部分に関数を置くこともできます。ただ、あまり複雑なことはさせないのがマナーです。

あ、多分これが正解(というか現在の知識でできるプログラム)ですね。まだ%sを習ってなかったので。しかし先ほどジェミニ先生が言ってた公式がちらっと思いついたので使ってしまいました。

2. ポインタ(変数)にメッセージを代入する

「表示するメッセージ」を一旦、変数に取っておく方法です。

char *msg = (a == b) ? "同じです" : "違います";
printf("それらの値は%s\n", msg);

※ char * は「文字列を指す変数(ポインタ)」です。後ほど学習すると思いますが、これを使うとプログラムがより柔軟になります。

いや、ポインタはまだできないよ

初めて使った %s は、「string(文字列)」 の頭文字です。

  • %d:整数(decimal)
  • %f:実数(float)
  • %s:文字列(string)

このように使い分けます。今回のあなたのコードは、この %s を使うことで「文章の組み立て」を非常にスマートにこなしていました!

はい、どうも。今日はここで終わります。