条件分岐(教科書5章)

これまで扱ってきたプログラムは順次実行のみ、すなわち、上から下に一本道で進むプログラムであった。今回は、条件に応じて実行内容を切り替える「条件分岐」について説明する。

プログラムの処理手順の基本は順次実行、条件分岐、繰り返し(次回で説明)の3つである。どんな複雑な処理手順でもこれらの組み合わせで成り立っている。

条件とは

例えば次のような質問文を考えてみよう。

○○さんは大学生ですか?(○○さんは誰か特定の人)

答はYesかNoのどちらかである。次の質問はどうだろう。

リンゴはバナナですか?

答はNoに決まっているが、形式的にはこれもYesかNoで答えられる質問である。

リンゴとバナナ、どちらがミカンですか?

この問いはYesかNoで答えられないばかりか、質問自体がナンセンスである。

京都産業大学は大きな大学ですか?

これはYesかNoで答えられるが「大きな大学」の基準が不明瞭なので、回答者によって答えは異なるだろう。

京都の市バスの均一区間内運賃はいくらですか?

この質問はYesかNoでは答えられない。しかし次のようにすると答えられるようになる。

京都の市バスの均一区間内運賃は230円ですか?

さて、論理学や数学の世界で「命題」という言葉がある。命題とは、正しいか(真 true)正しくないか(偽 false)かを確定的に判定できる文や式である。

練習:上の例はそれぞれ命題か命題でないか答えよ。

練習:命題となる文を考えてみよう。

冒頭で「条件分岐」は条件に応じて実行内容を切り替える、と説明した。プログラミング言語においては、この条件は命題でなければならない。更に、条件となる命題はプログラム言語が扱える式で表現しなければならない。

高度なプログラムでは人間のような曖昧な判断を扱うことができるものがあるが、命題を複雑に組み合わせることで実現している。

条件分岐のごく簡単な例(教科書p.118〜120)

次のようなプログラムを書くことを考えてみよう:

宝箱が3つあり、1つは罠であるとする。どれを開けるか選ばせ、罠の宝箱を開けたら「罠だった」とメッセージを表示する。

「罠の宝箱を開けたら」の部分が条件となる。

scanf関数で整数値以外の値を読み取る方法は説明していないので、宝箱に番号を付けて指定させることにしよう。そして、プログラムを例えば次のように言い換えてみる:

1〜3の番号の書かれた宝箱があり、1と書かれた宝箱は罠であるとする。どれを開けるか番号を入力させ、入力された番号が1であれば「宝箱は罠だった」とメッセージを表示する。

簡単のため、1〜3以外の値は入力されないものとする。

このように表現すると「入力された番号が1であれば」が条件となる。

与えられた条件が真か偽かを判定し、真の場合に指定された文を実行するにはif文を使う。具体的には、このプログラムは次のように書ける:

/*****
    treasure.c
    宝箱を開けてみる
    M.Minakuchi
*****/

#include <stdio.h>

int main() {
    int box;  // 選んだ宝箱の番号

    printf("宝箱が3つある!どれを開けますか?(1か2か3): ");
    scanf("%d", &box);

    if (box == 1)  printf("宝箱は罠だった\n");

    return 0;
}

練習:上のプログラムを入力、コンパイル、実行して動作を確認しよう。コメントや表示メッセージはこの通りでなくてもよい。入力値は1、2、3のそれぞれで試すこと。

ここでポイントとなるのは

if (box == 1)  printf("宝箱は罠だった\n");

の箇所である。if文の基本的な文法は次のようになっている:

if (条件式) [条件を満足したときに実行される式];

条件式は、C言語では0の場合は偽、0以外の場合は真と決められている※。しかし、0か0でないか、だけでは条件として扱いにくい。そこで、2つの値を比較する比較演算子が用意されている。上のプログラムの例ではbox == 1が相当する。比較演算子については後ほど詳しく説明する。

※新しめのプログラミング言語では真を表す値trueと偽を表す値falseが用意されているものが多い。C言語の時代はそのような考え方がまだなく整数値で真偽を表していたが、デメリットが多い。

つまり、
条件 box == 1 が成り立つ場合に、
実行される式はprintf文
となっている。

このプログラムの処理の流れを図示すると次のようになる:

これはフローチャートと呼ばれる図の描き方である。教科書でも使用されている。具体的な書き方は「フローチャート」で検索すると説明ページがすぐに見つかるだろう。

条件式の == に注意!! == は比較演算子(または関係演算子)の一つで、左辺と右辺の値が等しいかどうかを判定するために使う。代入演算子 = と間違わないように!!

【注意!!】C言語では=と==を間違えて書いてしまってもコンパイルが通ってしまう(最近のコンパイラは警告を出してくれるようだが)。この間違いを見つけるには実行してみて意図したとおりに動作するかどうかを確かめるしかない。熟練者でも間違うことがあり、間違いを見つけにくいので厄介である。

【上記の高度な補足】C言語では比較演算子の判定結果は、正しい場合(真)は1、正しくない場合(偽)は0という整数値で表されている。また、if文の条件式は、0以外なら真として扱われることになっている。一方、代入文=の実行結果は代入した値となるという決まりがある。このため、条件式のところに代入文を書いてしまっても、なんらかの値が条件として判定されるのでコンパイルエラーにならない。これはC言語が作られた時代が古かったため仕方の無いことである。なお、条件式の結果の値(0または1)を計算に使うようなプログラムは、意図しない不具合の原因になりがちなので通常は書くべきではない。

練習:box == 1の部分をbox = 1と変えてみて、どうなるか確かめよう。

練習:罠の宝箱を2番に変更してみよう。

複数文への条件分岐(ブロック)(教科書p.120〜124)

上記の例題で1番の宝箱を選んだ場合に、「宝箱は罠だった」というメッセージだけでなく「敵が現れた」というメッセージも表示したい、とする。1つのprinft関数で一度にメッセージを表示することは可能だが、ここでは2つのprintf関数で分けて表示するとしよう。

先ほどのプログラムのif文を使うと、次のように書ける:

/*****
    treasure.c
    宝箱を開けてみる
    M.Minakuchi
*****/

#include <stdio.h>

int main() {
    int box;  // 選んだ宝箱の番号

    printf("宝箱が3つある!どれを開けますか?(1か2か3): ");
    scanf("%d", &box);

    if (box == 1)  printf("宝箱は罠だった\n");
    if (box == 1)  printf("敵が現れた\n");

    return 0;
}

これでも間違いではないが、毎回if文で同じ条件を判定するのも間抜けな感じがするし、うっかり条件を書き間違えてしまうかもしれない。

このような場合、C言語では複数の実行文を1つにまとめる{ }を使うとよい。if文の場合、書き方は次のようになる({と}の間の式はいくつあってもよい):

if (条件式) {
    [条件を満足したときに実行される式1];
    [条件を満足したときに実行される式2];
    [条件を満足したときに実行される式3];
    .....(以下省略)
}

練習:上記のプログラムを{ }を使った書き方に修正しよう。

このプログラムの処理をフローチャートで描くと次のようになる:

ブロックとインデント

{と}で囲まれた範囲をブロックblockと呼ぶ。main関数の{と}も同様である。ブロックは複数の処理(実行文)をひとかたまりにして扱う意味がある。このような構造を視覚的に分かりやすくするために、ブロック内を字下げ(インデント)して書くのが慣習となっている。例えば、

    if (box == 1) {
    printf("宝箱は罠だった\n");
    printf("敵が現れた\n");
    }

だと、if文の条件が成立したときにどこが実行されるのか分かりにくい(この例では2つしかないので見間違うことはないかもしれないが、何行にも渡るとややこしくなってくる)。

次のような字下げがぐちゃぐちゃなプログラムを書いてはいけない。間違いの元であるし、プログラミングが理解できていないと白状しているようなものである。

    if (box == 1) {
  printf("宝箱は罠だった\n");
     printf("敵が現れた\n");
   }

そこで、

    if (box == 1) {
        printf("宝箱は罠だった\n");
        printf("敵が現れた\n");
    }

このように字下げをしておく。字下げの量(何文字分スペースまたはタブを入れるか)は2文字、4文字、8文字などの流派があるが、自分で見やすいと思う字数で統一するとよい。プログラミング用のエディタでは、拡張子が.cのファイルを編集している場合はC言語のプログラムと解釈して、自動的に字下げを合わせてくれる機能があるので活用するとよい。

Emacsの場合、もし字下げが正しくなくなった場合はTabキーを押すと、その行のインデントを直してくれる。学部配布のEmacsではF6(fnキーを押しながらF6と書いてあるキーを押す)で全体を直してくれる。

VS Codeの場合、範囲を選択して⌘K⌘Fでインデントを直してくれる。Option+Shift+Fで全体を直してくれる。

もしインデントがおかしい場合、{や}を書き忘れているなどの間違いをしていることがある。このようにして「変だな」と思ったら書き間違えてないかよく見るとよい。同様に、コメントや文字列などは色付きで表示されるので普段と雰囲気が違っている場合は何か書き間違えている可能性がある。

{ }を書き忘れるとどうなるか?上記のプログラムなら次のようになる(一部のみ掲載):

    if (box == 1)
        printf("宝箱は罠だった\n");
        printf("敵が現れた\n");

練習:{}を抜いて実行してみて、どうなるか確認しよう。

{ }が無いので、if文の条件が満足されるときに実行される文は次のprintf文だけとなる。そのため、2つめのprintf文はif文に無関係に、常に実行されることになる。このような間違いを防ぐために、if文では常に{と}を使って書く、というように習慣づけてもよいだろう。

この資料の著者は、処理が1行だけの場合、後から修正する可能性が低く処理内容が一目瞭然な場合は上記の例のようにif文の後ろにつなげて書いてしまうようにしている。読みやすく、間違いの起こりにくい書き方で、プログラム全体で統一して書けばよい。

else さもなければ(教科書5.3節)

宝箱の例題をさらに変えて、下線部の内容を追加してみよう:

1〜3の番号の書かれた宝箱があり、1と書かれた宝箱は罠であるとする。どれを開けるか番号を入力させ、入力された番号が1であれば「宝箱は罠だった」「敵が現れた」とメッセージを表示する。それ以外の番号であれば「あなたは宝を手に入れた」とメッセージを表示する。

ここまでのif文では条件が成り立った場合(真であった場合)に実行される分岐を書いていたが、elseを組み合わせて「条件が成り立たなかった」場合(偽であった場合)の処理も書くことができる。書き方は次のようになる:

if (条件式) {
    [条件を満足したときに実行される式1];
    [条件を満足したときに実行される式2];
    [条件を満足したときに実行される式3];
    .....(以下省略)
} else {
    [条件を満足しなかったときに実行される式1];
    [条件を満足しなかったときに実行される式2];
    [条件を満足しなかったときに実行される式3];
    .....(以下省略)
}

条件を満足したときに実行される式も条件を満足しなかったときに実行される式も、1つしかない場合は{ }は省略可能であるが、間違いの元となりやすいので常に{ }を書くことをお薦めする。

条件は命題なので、真か偽かどちらかにしかならないことを思い出してほしい。つまり、if-elseは条件に応じてどちらかのブロックが必ず実行されることになる。

C言語の文法として、elseは常にifと組み合わせになっている必要がある。ifを書かずにelseだけを書くことはできない。

if文の条件が成立したときに実行する文が無い(空っぽ)という書き方は可能だが、そのような場合は条件を見直した方がよい)。

練習:if-elseを使って、上記のプログラムを書いてみよう。

このプログラムの処理をフローチャートで描くと次のようになる:

関係演算子(教科書5.1節)

条件を判定するための比較演算子は次の6種類がある:

== 左辺と右辺の値が等しい
!= 左辺と右辺の値が異なる
> 左辺が右辺より大きい
>= 左辺が右辺より大きいか等しい
< 左辺が右辺より小さい
<= 左辺が右辺より小さいか等しい

== と != 、> と <= 、< と >= は互いに補完し合う関係にあることに注意。

関係演算子は2つの値の比較にしか使えないことに注意。例えば、x < y < z のように3つの値の大小関係を表現することはできない(詳しくは後の回で説明する)。

何か整数値を入力させ、入力された値の絶対値を表示するプログラムabsolute.cを作成せよ。

【実行例(下線の部分は入力した整数値の例)】
$ gcc -o absolute absolute.c
$ ./absolute
input number: 123
123
$ ./absolute
input number: -456
456

絶対値の求め方を考えてみると、値が正か0の場合はそのままでよく、負の場合は符号を反転(マイナスをプラスに変換)させればよい。すると、例えば次のようなプログラムを作れば良いことになる(変数名は例。他の名前の変数でもよい):

1) 何か整数値を入力させ変数numberに格納する。
2) 変数numberの値が負の場合は符号を反転させた値を新たな変数numberの値とする。
3) 変数numberの値を表示する。

符号を反転させるには、代入文を使って

number = -number;

と書ける。あるいは、

number *= -1;

でもよい(それぞれ意味を考えてみよう)。

練習:処理の流れをフローチャートで描いてみよう。
ヒント:「変数numberの値が負の場合は」が条件になっている。

練習:absolute.cを完成させよ。

条件の組み合わせ

複数の値との比較

最初に出てきた宝箱の練習問題で、3つの宝箱それぞれの内容が異なるようにしてみよう:

練習:1〜3の番号の書かれた宝箱がある。どれを開けるか番号を入力させ、入力された番号が1であれば「宝箱は罠だった」、2であれば「あなたは宝を手に入れた」、3であれば「宝箱は空っぽだった」とメッセージを表示するように、treasure.cを修正せよ。

ここまでの例ではif-elseを使って、条件が成立した場合と成立しなかった場合の2つに処理を分岐させた。それに対し、この例では処理を3つに分岐させなければならない。

この練習問題の場合は実は簡単にプログラムできる。

if (box == 1)  printf("宝箱は罠だった\n");
if (box == 2)  printf("あなたは宝を手に入れた\n");
if (box == 3)  printf("宝箱は空っぽだった\n");

実行文が1行だけなので{ }を使わずに書いているが、最初のうちは{ }を書いた方が間違いがないだろう。

宝箱は1か2か3のいずれかなので、このように条件文を3つ連続して書けばいずれかの条件に該当する。該当する条件以外の条件には該当しないことに注意。

なお、このように整数値に応じて処理を振り分ける場合はif文を連ねて書くよりも、次々回紹介するswitch-case文を使った方が読みやすくなる。

値の範囲での条件分岐

値の範囲を指定する際に、それぞれの条件がお互いに重複しない範囲として比較演算子を使って書ける場合は、上の例と同じようにif文を連ねるだけで済む。

練習:整数値を入力させ、入力された値が負の場合は「マイナス」、0の場合は「ゼロ」、正の場合は「プラス」と表示するプログラムsign.cを作成せよ。

一方、比較演算子を使って単純に条件を書けない例として、次のような問題を考えてみよう:

整数値を入力させ、入力された値が10以上100未満の場合は「2桁の値」と表示するプログラムtwoDigits.cを作成せよ。

値の範囲は数式では10 <= x < 100のように書くことができるが、C言語ではこのような書き方は使えない。

実はC言語では、
if (10 <= x < 100) printf("2桁の値\n");
と書いてもコンパイルは通ってしまう。しかし、実行させるとxの値に関わらず、常に条件が成立してしまう。
C言語のプログラミングに慣れた人はなぜこうなるか考えてみよう(ヒント:この条件式は、まず10 <= xが判定され、その結果の値が100より小さいか判定される。C言語では真は1、偽は0で表される)。

このような場合、2つの不等式に分けて考える必要がある。つまり、10 <= x < 100は、10 <= xが成立しており、さらに(かつ)、x < 100が成立している、と考える。

「かつ」を表す演算子は存在するが後の回で解説するとして、ここでは簡単な書き方を紹介する。ある条件が成立している時に、さらに別の条件が成立しているかどうかを判定する方法の一つは、if文の中にif文を書く方法である。書き方としては次のようになる:

if (条件1) {
    if (条件2) {
        [条件1と条件2が共に満足されたときに実行される式1];
        [条件1と条件2が共に満足されたときに実行される式2];
        [条件1と条件2が共に満足されたときに実行される式3];
        ....
    }
}

練習:10 <= x < 100 を判定する条件文を書いてtwoDigits.cを完成させよう。

なお、この書き方は特別な書き方ではなく、単にif文を組み合わせただけにすぎないことに注意。else節も加えて、他の部分も全部書いてみると次のようになる:

if (条件1) {
    [条件1が満足されたときに実行される式1];
    [条件1が満足されたときに実行される式2];
    ....
    if (条件2) {
        [条件1と条件2が共に満足されたときに実行される式1];
        [条件1と条件2が共に満足されたときに実行される式2];
        ....
    } else {
        [条件1が満足され、条件2が満足されなかったときに実行される式1];
        [条件1が満足され、条件2が満足されなかったときに実行される式2];
        ....
    }
    [条件1が満足されたときに実行される式3];
    [条件1が満足されたときに実行される式4];
    ....
}

条件1が満足されなかった場合は条件1に対するelse節に書けばよいので、条件1と条件2の真偽の組み合わせ4パタンを網羅することができる。

条件の組み合わせは、ここで説明したようにif文の組み合わせでも書けるが、後で説明する論理演算子を使って書くこともできる。

段階的な条件分岐(教科書5.4節)

テストの点数を入力し、点数が80点以上なら「優」、「優」ではなく60点以上なら「可」、「優」でも「可」でもない場合「不可」と表示するプログラムexam.cを作成せよ。

【実行例(下線部は入力例)】
$ gcc -o exam exam.c
$ ./exam
点数を入力してください: 90
優
$ ./exam
点数を入力してください: 70
可
$ ./exam
点数を入力してください: 50
不可
$

条件が少々複雑なので、順番に考えていこう。まず、優であるか判定する条件は次のようになる。

if (score >= 80) {
    printf("優\n");
}

次に、「可」の条件を考えてみる。『「優」ではなく』というのはelseを使って次のように書ける。

if (score >= 80) {
    printf("優\n");
} else {
    // 優ではない場合
}

「優」ではない場合に60点以上なら「可」なのだから、elseの中で条件判定をすればよい。

if (score >= 80) {
    printf("優\n");
} else {
    // 優ではない場合
    if (score >= 60) {
        printf("可\n");
    }
}

ここまでで「優」と「可」の判定ができた。残りの「不可」は、「優」でも「可」でもない場合だから、「可」を判定するif文が成り立たなかった場合、となるので、elseを使って次のように書ける。

if (score >= 80) {
    printf("優\n");
} else {
    // 優ではない場合
    if (score >= 60) {
        printf("可\n");
    } else {
    // 優でも可でもない場合
        printf("不可\n");
    }
}

これでもOKだが、もう少しすっきり書いてみよう。if-else節は全体で1つの文として扱うことができるので、1つめのelse節の{ }は省略することができ、次のように書き直せる。

if (score >= 80) {  // もし80点以上なら
    printf("優\n");
} else if (score >= 60) {  // さもなくば、もし60点以上なら
    printf("可\n");
} else {  // さもなくば
    printf("不可\n");
}

意味的には、上記のプログラムの断片にコメントで記入してあるように、80点以上、80点未満60点以上、60点未満、と、点数の範囲を分割したような形となる。

形式的には、else if という構文として解説している本なども多いが(確かに、そう覚えてしまった方が手っ取り早い)、実体は上記説明したとおりif-elseの組み合わせに過ぎない。いずれにしても、このように書くと条件がすっきりして振り分け方法が明確になる。簡潔に書くことはプログラムのミスを防ぐ意味で重要である。

まとめると、if-else if-else型の構文として覚えてしまうとよい。英語の意味の通り、else if は「さもなくば、もし」。条件が3つある例は次のようになる(4択の条件分岐になる)。else ifは好きなだけ増やすことができる。条件は上から順に判定され、いずれかの条件が成り立った場合は以後の条件は飛ばされることに注意。

if (条件1) {
    // 条件1が成り立ったときに実行されるブロック
} else if (条件2) {
    // 条件1が成り立たず、条件2が成り立ったときに実行されるブロック
} else if (条件3) {
    // 条件1と条件2が成り立たず、条件3が成り立ったときに実行されるブロック
} else {
    // ここまでの条件がすべて成り立たなかったときに実行されるブロック
}

練習:説明したような条件文の組み合わせを使って、exam.cを完成させよ。

確認課題

以下、出来たら教員に確認を受けること。原則的に易しい順となっているが、順序どおりに取り組む必要はない。また、多目に用意しているので授業時間内にすべてができることを求めるものではない。Do your best!

確認課題1. 奇数判定

自然数(正の整数値)を入力させ、入力された値が奇数なら"odd"と表示するプログラムodd.cを作成せよ。入力値が負の値の場合は考慮しなくてよい。

【実行例(下線の部分は入力した整数値の例)】
% gcc -o odd odd.c
% ./odd
input number: 11
odd
% ./odd
input number: 12
%

ヒント:奇数=2で割り切れない=2で割った余りは1。剰余演算子%を使うとよい。

確認課題2. 奇数?偶数?

自然数(正の整数値)を入力させ、入力された値が奇数なら"odd"、偶数なら"even"と表示するプログラムoddOrEven.cを作成せよ。入力値が負の値の場合は考慮しなくてよい。

【実行例(下線の部分は入力した整数値の例)】
% gcc -o oddOrEven oddOrEven.c
% ./oddOrEven
input number: 11
odd
% ./oddOrEven
input number: 12
even
%

確認課題3. りんご、みかん、ばなな

整数値を入力させ、入力された値を3で割った余りが1の場合は"apple"、2の場合は"orange"、0の場合(割り切れる場合)は"banana"と表示するプログラムfruits.cを作成せよ。

【実行例(下線の部分は入力した整数値の例)】
% gcc -o fruits fruits.c
% ./fruits
input number: 4
apple
% ./fruits
input number: 8
orange
% ./fruits
input number: 12
banana
%

確認課題4. どっちが大きい?

2つの整数値を入力させ、1つめの値と2つめの値の大小を比較して、大きい、小さい、等しいのそれぞれの場合に応じて、下の実行例のようにメッセージを表示するプログラムbigOrSmall.cを作成せよ。

【実行例(下線の部分は入力した整数値の例)】
% gcc -o bigOrSmall bigOrSmall.c
% ./bigOrSmall
1つめの値: 5
2つめの値: 7
5は7より小さい
% ./bigOrSmall
1つめの値: 5
2つめの値: 1
5は1より大きい
% ./bigOrSmall
1つめの値: 5
2つめの値: 5
5と5は等しい
%

確認課題5. 2つとも1?

2つの整数値を入力させ、1つめの値と2つめが共に1の場合"one!!"と表示するプログラムone.cを作成せよ。

【実行例(下線の部分は入力した整数値の例)】
% gcc -o one one.c
% ./one
1つめの値: 1
2つめの値: 1
one!!
% ./one
1つめの値: 0
2つめの値: 2
% ./one
1つめの値: 1
2つめの値: 0
%

確認課題6. 成績判定+

テストの点数を入力し、点数が90点以上なら「秀」、「秀」ではなく点数が80点以上なら「優」、「秀」か「優」ではなく70点以上なら「良」、「秀」か「優」か「良」ではなく60点以上なら「可」、「秀」「優」「良」「可」のいずれでもない場合「不可」と表示するプログラムexam2.cを作成せよ(「段階的な条件分岐」で作成したプログラムをコピーして修正すればよい)。

【実行例(下線部は入力例)】
% gcc -o exam exam.c
% ./exam
点数を入力してください: 90
秀
% ./exam
点数を入力してください: 89
優
% ./exam
点数を入力してください: 75
良
% ./exam
点数を入力してください: 60
可
% ./exam
点数を入力してください: 50
不可
%

確認課題7. 衝突判定 [advanced]

次のプログラムcheckHit.cをHandyGraphicを使用して作成せよ:
ウィンドウの大きさを400x400とし、円1の中心を(200, 200)、半径を150とする。円2の中心座標と半径を入力させ、円1は塗りつぶし無しで描く(輪郭線の太さは初期状態のままでよい)。円2は、円1と円2が「ぶつかっている」場合は赤色、「ぶつかっていない」場合は青色で塗りつぶして描く。

2つの円が「ぶつかっている」という状態は「2つの円が互いに重なっている」と言い表せる。「互いに重ならない」状態と「互いに重なる」状態の間に「互いに接する」という状態がある。ここでは互いに接している状態は「ぶつかっていない」ものとしよう。

2つの円が「接している」状態は、2つの円の中心の距離が2つの円の半径の和と等しい、と表すことができる。「ぶつかっている」状態は、2つの円の中心の距離が2つの円の半径の和よりも小さい、と表すことができる。

距離を求めるには平方根を使うが、距離は正の値なので値の大小を比較するだけなら両辺を2乗した値で比較しても同じことになる。C言語で平方根を求めるには数学用の関数と実数型の変数を使う必要があるが、両辺を2乗すれば整数のまま計算することができる。

HandyGraphicを使用する際には
#include <handy.h>
を書くことと、コンパイルにはhgccコマンドを使用することを忘れずに。

本日の提出課題

提出課題1. 手持ちの金額と、ある品物1個の値段(単価)と、買いたい個数を入力させ、買える場合は「買える。おつりは○○円。」、買えない場合は「買えない。××個までなら買える。」と表示するプログラムshopping.cを作成せよ。ただし、入力される値は0より大きい正の整数であるとする(変な値を入力された場合は考慮しなくてよい)。

提出期限:次の土曜日の24:00まで

【実行例(下線部は入力例)】
% gcc -o shopping shopping.c
% ./shopping
手持ちの金額: 1000
単価: 230
個数: 3
買える。おつりは310円。
% ./shopping
手持ちの金額: 1000
単価: 200
個数: 5
買える。おつりは0円。
% ./shopping
手持ちの金額: 1000
単価: 230
個数: 5
買えない。4個までなら買える。
%

腕に覚えのある人は、まず上の説明だけで考えて作ってみて欲しい。どこから手をつけてよいか分からない人は、次のように考えてみよう(これ以外の処理方法で作成しても、正しく動作するのであれば構わない):

手持ちの金額と、ある品物1個の値段(単価)と、買いたい個数を入力させる。次に、買おうとしている品物の合計金額を計算する。手持ちの金額が品物の合計金額と同じか多い場合は、おつりを計算し、「買える。おつりは○○円。」と表示する。そうでない場合(手持ちの金額が品物の合計金額より少ない場合)は買える最大の個数を計算し、「買えない。××個までなら買える。」と表示する。

さらに、どのように計算してよいか分からない人は、次のヒントを見て考えてみよう:

ヒント:
買おうとしている品物の合計金額 = 単価 × 個数
おつり = 手持ちの金額 - 買おうとしている品物の合計金額
買える最大の個数 = 手持ちの金額 / 単価 (整数どうしの割り算なので余りは無視される)

提出課題2. 標準体重(健康的であるとされる体重)は簡易的に次の式で計算できる。

標準体重[kg] = 身長[cm] - 105

身長と体重を入力させ、次のように肥満度をチェックするプログラムweight.cを作成せよ。

体重が標準体重の1割増より重い場合:太りすぎのメッセージを表示する
体重が標準体重の1割増〜1割減の範囲の場合:適切のメッセージを表示する
体重が標準体重の1割減より軽い場合:やせ過ぎのメッセージを表示する

なお、整数型のみで計算するので、1割増、1割減は小数点以下は切り捨てでよい(計算結果を整数型の変数に代入すると自動的にそうなる)。例えば、標準体重が69kgのとき、正確には1割増は75.9kg、1割減は62.1kgであるが、整数型で計算するとそれぞれ75kg、62kgとなる。

提出期限:次の授業開始時まで

【実行例(下線部は入力例)】
% gcc -o weight weight.c
% ./weight
身長: 175
体重: 68
ちょうどよいです。
% ./weight
身長: 175
体重: 78
太りすぎです。
% ./weight
身長: 175
体重: 58
やせ過ぎです。
%

なお、標準体重の1割増、1割減を整数型のみで計算するには次のようにして計算するのがよい(掛け算を先に行うことに注意。割り算を先に行うとうまくいかない)。
[標準体重] * 110 / 100
[標準体重] * 90 / 100

[標準体重] * 1.1 や [標準体重] * 0.9 とした場合でも自動的に整数型に変換されるので特に問題はないが、小数点以下が自動的に切り捨てられてしまっていることは意識しておく必要がある。