switch文 解答ページ | Programming Place Plus 新C++編

トップページ新C++編switch文

このページの概要

このページは、練習問題の解答例や解説のページです。



解答・解説

問題1 (確認★)

電卓プログラムを改造して、剰余を計算する演算子「%」も受け付けられるようにしてください。


ほかの四則演算にならって、コードを追加するだけです。次のようになります。

#include <iostream>
#include <string>

int main()
{
    constexpr auto addition = '+';
    constexpr auto subtraction = '-';
    constexpr auto multiplication = '*';
    constexpr auto division = '/';
    constexpr auto modulo = '%';

    std::cout << "Please enter the formula.\n";
    int value1 {};
    std::string op {};
    int value2 {};
    std::cin >> value1 >> op >> value2;

    switch (op[0]) {
    case addition:
        std::cout << value1 + value2 << "\n";
        break;
    case subtraction:
        std::cout << value1 - value2 << "\n";
        break;
    case multiplication:
        std::cout << value1 * value2 << "\n";
        break;
    case division:
        std::cout << value1 / value2 << "\n";
        break;
    case modulo:
        std::cout << value1 % value2 << "\n";
        break;
    default:
        std::cout << "The formula is incorrect.\n";
        break;
    }
}

実行結果:

Please enter the formula.
10 % 3  <-- 入力した計算式
1

問題2 (確認★)

次のプログラムがコンパイルエラーになる理由を説明してください。

#include <iostream>

int main()
{
    int value {3};

    switch (value + 1) {
    case 0:
        break;
    case 1:
        std::cout << "*\n";
        break;
    case 1 + 1:
        std::cout << "**\n";
        break;
    case 0:
        std::cout << "\n";
    }
}


コンパイルエラーの原因は、同じ値になる caseラベルが2つあることです。このような重複は許されません(本編解説)。

switch (value + 1) のように、計算をともなう条件式はなんら問題ありません(条件「式」ですから、計算式を書いてかまいません)。value + 1 の結果は 4 であり、該当するラベルがありませんが、これも問題ありません。単に、どれも実行されないだけです。

case 1 + 1: のように、caseラベルのところで計算式を使うことも、コンパイル時に値が確定できるのなら問題ありません。

最後のところに break; がありませんが、これも問題はありません。switch文の終わりの } に行き着いたら、switch文自体が終わります。

問題3 (基本★★)

1~13 のいずれかの整数の入力を受け取ります。この整数をトランプの数字に見立てて、1 は A、11 は J、12 は Q、13 は K、それ以外の数はそのまま出力するプログラムを作成してください。


特別なあつかいをしなければならないのは、1、11、12、13 の4パターンです。これらにだけ caseラベルを用意し、ほかは defaultラベルの方に進ませればいいでしょう。たとえば次のようになります。

#include <iostream>

int main()
{
    std::cout << "Please enter the integer. (1~13)\n";
    int value {};
    std::cin >> value;

    switch (value) {
    case 1:
        std::cout << "A\n";
        break;
    case 11:
        std::cout << "J\n";
        break;
    case 12:
        std::cout << "Q\n";
        break;
    case 13:
        std::cout << "K\n";
        break;
    default:
        std::cout << value << "\n";
        break;
    }
}

実行結果:

Please enter the integer. (1~13)
1  <-- 入力した整数
A

実行結果:

Please enter the integer. (1~13)
13  <-- 入力した整数
K

実行結果:

Please enter the integer. (1~13)
5  <-- 入力した整数
5

トランプに見立てている以上、1~13 以外の入力を不正なものとみなすという考え方をすることもできるでしょう。次のように書けます。

#include <iostream>

int main()
{
    std::cout << "Please enter the integer. (1~13)\n";
    int value {};
    std::cin >> value;

    switch (value) {
    case 1:
        std::cout << "A\n";
        break;
    case 2:
    case 3:
    case 4:
    case 5:
    case 6:
    case 7:
    case 8:
    case 9:
    case 10:
        std::cout << value << "\n";
        break;
    case 11:
        std::cout << "J\n";
        break;
    case 12:
        std::cout << "Q\n";
        break;
    case 13:
        std::cout << "K\n";
        break;
    default:
        std::cout << "error.\n";
        break;
    }
}

実行結果:

Please enter the integer. (1~13)
14  <-- 入力した整数
error.

defaultラベルを不正な入力の処理に使うようにしました。

入力が 2~10 のときの処理が全部同じになりますが、こういうときにはフォールスルーを利用して書けます(本編解説)。フォールスルーの濫用は避けたほうがいいですが、このサンプルのように明らかに同じ処理でいい(後から部分的に処理が変更されるとも思えないような)場面では使ってもいいでしょう。

問題4 (応用★★★)

あまり奇麗なプログラムにはならないものの、ここまでの知識だけでも、電卓プログラムを改造して、「3 + 2 * 4」のように、整数3つ演算子2つの計算式に対応させることができます(逆に「3 + 2」で止められなくなりますが)。そのようなプログラムを書いてみてください。


たとえば、次のようになります。

#include <iostream>
#include <string>

int main()
{
    constexpr auto addition = '+';
    constexpr auto subtraction = '-';
    constexpr auto multiplication = '*';
    constexpr auto division = '/';

    std::cout << "Please enter the formula.\n";
    int value1 {};
    std::string op1 {};
    int value2 {};
    std::string op2 {};
    int value3 {};
    std::cin >> value1 >> op1 >> value2 >> op2 >> value3;

    switch (op1[0]) {
    case addition:
        switch (op2[0]) {
        case addition:
            std::cout << value1 + value2 + value3 << "\n";
            break;
        case subtraction:
            std::cout << value1 + value2 - value3 << "\n";
            break;
        case multiplication:
            std::cout << value1 + value2 * value3 << "\n";
            break;
        case division:
            std::cout << value1 + value2 / value3 << "\n";
            break;
        default:
            std::cout << "The formula is incorrect.\n";
            break;
        }
        break;
    case subtraction:
        switch (op2[0]) {
        case addition:
            std::cout << value1 - value2 + value3 << "\n";
            break;
        case subtraction:
            std::cout << value1 - value2 - value3 << "\n";
            break;
        case multiplication:
            std::cout << value1 - value2 * value3 << "\n";
            break;
        case division:
            std::cout << value1 - value2 / value3 << "\n";
            break;
        default:
            std::cout << "The formula is incorrect.\n";
            break;
        }
        break;
    case multiplication:
        switch (op2[0]) {
        case addition:
            std::cout << value1 * value2 + value3 << "\n";
            break;
        case subtraction:
            std::cout << value1 * value2 - value3 << "\n";
            break;
        case multiplication:
            std::cout << value1 * value2 * value3 << "\n";
            break;
        case division:
            std::cout << value1 * value2 / value3 << "\n";
            break;
        default:
            std::cout << "The formula is incorrect.\n";
            break;
        }
        break;
    case division:
        switch (op2[0]) {
        case addition:
            std::cout << value1 / value2 + value3 << "\n";
            break;
        case subtraction:
            std::cout << value1 / value2 - value3 << "\n";
            break;
        case multiplication:
            std::cout << value1 / value2 * value3 << "\n";
            break;
        case division:
            std::cout << value1 / value2 / value3 << "\n";
            break;
        default:
            std::cout << "The formula is incorrect.\n";
            break;
        }
        break;
    default:
        std::cout << "The formula is incorrect.\n";
        break;
    }
}

実行結果:

Please enter the formula.
3 + 2 * 4  <-- 入力した計算式
11

まず、std::cin で受け取るデータが「整数 演算子 整数 演算子 整数」という並びになるので、それに合うように、op2 と value3 を追加しています。

switch文で1つ目の演算子を使って分岐させる点は同じです。重要なのは、各caseラベルの処理の中で、さらに switch文を使うことです。caseラベルや defaultラベルのところに記述できるものは「文」であり、switch文を書くこともできます。

内側の switch文では2つ目の演算子を使って分岐します。あとは、2つの演算子と3つの整数を組み合わせた計算式を組んで、計算結果を出力させるだけです。

これで一応目的は果たせますが、あまり奇麗な方法ではありません(現状の知識ではこれが限界です)。奇麗でない主原因は、似たようなコードが何度も何度もあらわれている点です。似ているけれど違うコードなので、どこかでうっかり間違えていたときに気付きづらいことも問題です(1つ目の演算子が ‘-’ で、2つ目の演算子が / のときのコードだけが間違っている、といったことがあり得る)。

また、さらに計算式を長くしたいといわれると、倍以上のコード量に膨らみ、ネストも深くなっていくことも辛いところです。短い計算式と長い計算式に同時に対応できるコードにすることもできません。


参考リンク



更新履歴




はてなブックマーク に保存 Pocket に保存 Facebook でシェア
X で ポストフォロー LINE で送る noteで書く
rss1.0 取得ボタン RSS 管理者情報 プライバシーポリシー
先頭へ戻る