以前本ブログでご紹介した「簡易電卓プログラム(第1版)」。
今回は、このプログラムを改良してみよう。
まずは、「簡易電卓プログラム(第1版)」を示しておこう。
//簡易電卓プログラム(第1版)
#include <stdio.h>
#include <string.h>
double result = 0.0;
char str[2];
//計算関数
double keisan(void){
    double num;
    printf("簡易電卓プログラム\n");
    printf("四則演算ができます。(+,-,*,/)入力例-> 3+5,続けて入力する-> *8,計算結果のクリア->c,終了->q;\n");
    printf(">");
    if (scanf("%lf", &result) != 1)
    {
        printf("計算できません\n");
        return 0;
    }
           
       
    do
    {
        //演算子の入力
        if (scanf("%1s", str) != 1)
        {
            break;                      // 入力が正常でなければループを終了
        }
       
        if (strcmp(str, "c") == 0)
          {
                printf("クリアします!\n");
                result = 0.0;              // "c" が入力された場合クリア
                keisan();
         }
        else if (strcmp(str, "q") == 0)
        {
            printf("終了します!\n");
            return 0;                       // "q" が入力された場合、計算を終了
        }
         
        
        // 数値の入力
        if (scanf("%lf", &num) != 1)
        {
            break;                       // 入力が正常でなければループを終了
        }
        switch (str[0])
        {
        case '+':
            result += num;
            break;
        case '-':
            result -= num;
            break;
        case '*':
            result *= num;
            break;
        case '/':
            if (num == 0.0)
            {
                printf( "ゼロでの除算はできません\n" );
                return 0;
            }
            result /= num;
            break;
       
        default:
            printf("演算記号の指定が違います\n");
            return 0;
        }
        printf("計算結果:%g\n", result);
    
  
    } while (1);
     return 0;
}
int main()
{
    keisan();
      
    return 0;
}
実行結果
簡易電卓プログラム
四則演算ができます。(+,-,*,/)入力例-> 3+5,続けて入力する-> *8,計算結果のクリア->c,終了->q;
>3+4
計算結果:7コードのポイント
- グローバル変数
- double result = 0.0; — 計算結果を保持。
 - char str[2]; — 入力された演算子またはコマンドを保持。
 
 - double result = 0.0; — 計算結果を保持。
 - keisan関数
- 最初に説明文を表示する。
 - scanf(“%lf”, &result); で最初の数式(数字と演算子)を読み取り、
 - 以降はループしながら、
- 演算子と数値を読み取り
 - 演算を実行して結果を更新
 - 計算結果を出力
 - 特別なコマンド (cやq) を処理する。 
 
 - 演算子と数値を読み取り
 
 - 最初に説明文を表示する。
 - main関数
 
keisan();を呼び出して実行する。
それでは、改良版を検討していこう。
① 演算子入力チェックが緩い
if (scanf(“%1s”, str) != 1)で演算子を判定しているが、本来なら「2文字目以降がないか」も厳密にチェックすべきであった。
✅ 改善
// 入力解析 (演算子 数値)
            if (sscanf(input, "%c%lf", &op, &num) == 2) {
                // 演算子が正しいかチェック
                if (strchr("+-*/", op) == NULL) {
                    printf("無効な演算子が入力されました。\n");
                    continue;
                }
② 異常入力後の処理が少し甘い
scanf("%lf", &num) などでエラーが起きた場合、「エラーメッセージを出す」だけで次の入力を促しているが、たとえば「アルファベットが混ざったとき」など、バッファにゴミが残ることがある。
✅ 改善
バッファクリアだけでなく、1回だけではなく複数回ループして完全クリアする方がベターであろう。
③ 終了コードを明示しない
正常終了(return 0;)してるが、エラー終了時(入力エラー時など)もreturn 0;になっている。
✅ 改善
例えば「異常終了なら return 1; 」と明示するとより親切だろう。
if (scanf("%lf", &result) != 1) {
    printf("数値の入力エラー。終了します。\n");
    clear_input_buffer();
    return 1;
}
④ ゼロ除算エラー時の動作がやや曖昧
✅ 改善(表示の工夫)
 printf("エラー: 0で割ることはできません。\n");
 printf("計算結果は変更されませんでした。別の演算を入力してください。\n");⑤ コード全体に関する小さな見た目改善
- 出力メッセージをきれいにそろえると、さらにユーザーにとって使いやすくなるだろう。
 - 例:計算結果出力後に
"------------------------------------"を表示して区切る。 
✅ 改善
printf("現在の計算結果: %g\n", result);
printf("------------------------------------\n");
それでは、改良版の全コードを表示しておこう。
// 簡易電卓プログラム(改良版)
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define STR_SIZE 100
// 入力バッファクリア関数
void clear_input_buffer(void) {
    int c;
    while ((c = getchar()) != '\n' && c != EOF) {}
}
// 初期メッセージ表示関数
void print_intro(void) {
    printf("\n--- 簡易電卓プログラム ---\n");
    printf("四則演算ができます。(+,-,*,/)\n");
    printf("入力例 -> 3+5\n");
    printf("続けて入力する -> *8\n");
    printf("計算結果のクリア -> c\n");
    printf("終了 -> q\n");
    printf("------------------------------\n");
}
int main(void) {
    double result = 0.0;
    double num = 0.0;
    char input[STR_SIZE];
    char op;
    int first_input = 1;
    print_intro();
    while (1) {
        if (first_input) {
            printf("最初の数式を入力してください (例: 3+5): ");
            if (fgets(input, sizeof(input), stdin) == NULL) {
                printf("入力エラー。終了します。\n");
                break;
            }
            // 入力が "q" または "c" だったらコマンド処理
            if (strcmp(input, "q\n") == 0) {
                printf("プログラムを終了します!\n");
                break;
            }
            if (strcmp(input, "c\n") == 0) {
                printf("クリアします!\n");
                result = 0.0;
                first_input = 1;
                print_intro();
                continue;
            }
            // 入力解析 (数値 演算子 数値)
            if (sscanf(input, "%lf%c%lf", &result, &op, &num) == 3) {
                switch (op) {
                    case '+': result += num; break;
                    case '-': result -= num; break;
                    case '*': result *= num; break;
                    case '/':
                        if (num == 0.0) {
                            printf("エラー: 0で割ることはできません。\n");
                            result = 0.0;
                            first_input = 1;
                            continue;
                        }
                        result /= num;
                        break;
                    default:
                        printf("無効な演算子が入力されました。\n");
                        result = 0.0;
                        first_input = 1;
                        continue;
                }
                printf("現在の計算結果: %g\n", result);
                printf("------------------------------\n");
                first_input = 0;
            } else {
                printf("無効な入力です。再入力してください。\n");
                continue;
            }
        } else {
            printf("続けて演算子と数値を入力してください (例: *8), c(クリア), q(終了): ");
            if (fgets(input, sizeof(input), stdin) == NULL) {
                printf("入力エラー。終了します。\n");
                break;
            }
            // "q" や "c" を単独入力した場合の処理
            if (strcmp(input, "q\n") == 0) {
                printf("プログラムを終了します!\n");
                break;
            }
            if (strcmp(input, "c\n") == 0) {
                printf("クリアします!\n");
                result = 0.0;
                first_input = 1;
                print_intro();
                continue;
            }
            // 入力解析 (演算子 数値)
            if (sscanf(input, "%c%lf", &op, &num) == 2) {
                // 演算子が正しいかチェック
                if (strchr("+-*/", op) == NULL) {
                    printf("無効な演算子が入力されました。\n");
                    continue;
                }
                switch (op) {
                    case '+': result += num; break;
                    case '-': result -= num; break;
                    case '*': result *= num; break;
                    case '/':
                        if (num == 0.0) {
                            printf("エラー: 0で割ることはできません。\n");
                            printf("計算結果は変更されませんでした。別の演算を入力してください。\n");
                            continue;
                        }
                        result /= num;
                        break;
                }
                printf("現在の計算結果: %g\n", result);
                printf("------------------------------\n");
            } else {
                printf("無効な入力です。再入力してください。\n");
                continue;
            }
        }
    }
    return 0;
}
実行結果
--- 簡易電卓プログラム ---
四則演算ができます。(+,-,*,/)
入力例 -> 3+5
続けて入力する -> *8
計算結果のクリア -> c
終了 -> q
------------------------------
最初の数式を入力してください (例: 3+5): 3+5
現在の計算結果: 8
------------------------------
続けて演算子と数値を入力してください (例: *8), c(クリア), q(終了): *8
現在の計算結果: 64
------------------------------
続けて演算子と数値を入力してください (例: *8), c(クリア), q(終了): /6
現在の計算結果: 10.6667
------------------------------
続けて演算子と数値を入力してください (例: *8), c(クリア), q(終了): q
プログラムを終了します!改良版まとめ
| ポイント | 内容 | 
|---|---|
fgets()で一括入力読取 | 行単位で入力を受け取るのでc/qの判定ができる | 
qで即終了、cで即クリア | どこでも c 、q が単独入力できる | 
sscanf()で柔軟な解析 | 数式/演算子+数値両方対応 | 
| 入力エラー時に再入力を促す | 再入力を案内する | 
| ゼロ除算時も安全にスキップ | 0除算でもプログラムは止まらない | 
今回は、ここまでとしよう。

 


コメント