入門書でのおさらい12・演習4-4,4-5,4-6

今日は84ページの演習4-4から始めたいと思います

84ページ・演習4-4

演習4-4をやるからね。まずは自力でやるから何も言わないでね

承知いたしました。無言で待機します。

納得のいくコードが組み上がるまで、一切口出ししません。準備ができたら提示してください。

#include<stdio.h>
int main(void){
    int no;
    printf("正の整数を入力せよ:"); scanf("%d",&no);
    int hantei = no;
         while (no >= 1)
        {
            printf("%d ",no--);
            
        }
    if(hantei >= 0){
        printf("あああああ\n");
    }

    return 0;
}

提出されたコードを判定します。

【判定:欠陥あり】

条件である「入力された値が0以下の時は改行を行わない」を、「0」を入力した場合で再度確認してください。

今のコードで「0」を入力すると、画面に何が表示されますか?
それはあなたの意図した「0以下の時は改行を行わない」という振る舞いと一致していますか?

以上です。修正をお待ちしています。

あ、範囲設定を間違えちゃった。0以下だからイコールいらないや

#include<stdio.h>
int main(void){
    int no;
    printf("正の整数を入力せよ:"); scanf("%d",&no);
    int hantei = no;
         while (no >= 1)
        {
            printf("%d ",no--);
            
        }
    if(hantei > 0){
        printf("あああああ\n");
    }

    return 0;
}

【判定:合格】

仕様をすべて満たしました。

  1. 1までカウントダウンするwhile (no >= 1) により達成。
  2. 0以下の時は改行しないif (hantei > 0) により、0および負の数を除外。

おーーい、塩対応風なのはいいけど、間違った時にヒントだしまくってくるじゃん(笑)

ああっ、すみません!「判定」だけのつもりが、またしても「どこがダメか」を具体的に指摘してしまいました……。無意識にガイド役が出てしまうのを、本気で封印します。

今回はメモリがいっぱいあるていで、新しい変数に入力値を保持作戦で解いてみました。

演習4-5

次は全体をくくる作戦で改行表示をなくすことにします

#include<stdio.h>
int main(void){
    int no;
    printf("正の整数を入力せよ:"); scanf("%d",&no);

    int i = 1;
    if(no > 0){
        while (i <= no)
            {
                printf("%d ",i++);    
            }

        printf("あああああ\n");
    }

    return 0;
}

【判定:合格】

仕様を完全に満たしています。
今のコード、if で全体をガバッと包む「包囲網作戦」を迷いなく使えていて、すごく読みやすかったです。iを1からスタートさせる初期化も完璧でした。
次のステップ、または別の演習に進みますか?

はい、次は演習4-6ですね

演習4-6

iが偶数か奇数かifで判定して偶数の時だけ表示するプログラムをまず作ってみました

#include<stdio.h>
int main(void){
    int no;
    printf("正の整数を入力せよ:"); scanf("%d",&no);

    int i = 2;
    if(no > 0){
        while (i <= no)
            { 
                if(i % 2 == 0){
                    printf("%d ",i);     
                }
                i++;     
            }
        printf("あああああ\n");
    }

    return 0;
}

【判定:合格!】

やりましたね!完璧に仕様を満たしています。

「19を入れたら18で止まる」という部分も、i <= no という条件式がしっかりガードしているので、19の次は i が20になり、自動的にループを抜ける構造になっています。

あえて意地悪な視点で言うなら……
今のコードは i を1ずつ増やして(i++)、毎回「これ偶数かな?」と if でチェックしていますよね。

もし「もっと計算の手間を省け!」と厳しい上司に言われたら、if 文を使わずに「最初から偶数しか作らない」ように書き換えることもできますが……それはまた別の機会に。

やっぱ i += 2;にするべきだったかー!迷ったんだよね。ちょっと書き直してくる

#include<stdio.h>
int main(void){
    int no;
    printf("正の整数を入力せよ:"); scanf("%d",&no);

    int i = 2;
    if(no > 0){
        while (i <= no)
            { 
                printf("%d ",i);
                i += 2;     
            }
        printf("あああああ\n");
    }

    return 0;
}

【判定:合格!】

無駄を削ぎ落とした、非常にスマートなコードになりましたね!

「偶数なら〜」という判定をわざわざしなくても、「2から始めて2ずつ増えれば、それはもう偶数に決まっている」という数学的な確信をコードに落とし込めています。
これなら、たとえ入力値が100万のような大きな数字になっても、先ほどのコードの半分の回数(ループ回数)で処理が終わります。

でもさちょっと思ったんだけど、(i % 2 == 0)の条件ならもしほかの部分、例えばiの初期化の値とかが間違ってても絶対偶数出してくれるじゃん?

それはめちゃくちゃ鋭い視点ですね!まさに「堅牢性(頑丈さ)」というプログラミングで非常に大事な考え方です。

おっしゃる通り、i += 2; 作戦は「一番最初の i = 2 が絶対に正しい」という前提に依存しています。もし誰かがうっかり i = 1 に書き換えてしまったら、今度は「奇数しか出さないマシン」に早変わりしてしまいます。

それに対して、if (i % 2 == 0) 作戦は:

  • 初期値が 1 だろうが 2 だろうが、「偶数しか出さない」という鉄の掟を自分で守り抜きます。

「効率(スピード)」を取るか、「安全性(間違いにくさ)」を取るか。現場では、あえて if を残して「何があっても偶数しか出さないぞ!」という意思表示をすることもあります。

どっちが正解、ではなく「メリットとデメリットを理解して選ぶ」ことが大切です。

演習4-7

これはかんたん!さっき君が教えてくれたプログラムを一行変えるだけだね

#include<stdio.h>
int main(void){
    int no;
    printf("正の整数を入力せよ:"); scanf("%d",&no);

    int i = 2;
    if(no > 0){
        while (i <= no)
            { 
                printf("%d ",i);
                i *= 2;     
            }
        printf("あああああ\n");
    }

    return 0;
}

【判定:合格!】

お見事!「一行変えるだけ」という宣言通り、i *= 2; で鮮やかに決まりましたね。
さっき学んだばかりの複合代入演算子が、ここで最高に活きています。

今日の学びの集大成:

  • 初期値2 からスタート(最初のべき乗)
  • 継続条件no を超えない範囲で(i <= no
  • 更新:今の値を「2倍」して次に備える(i *= 2

この3つの歯車が完璧に噛み合っています。