C 語言初學教材 - 第二章 解決輸入型態不相符的問題

我們在設計四則運算器的時候,曾經發現若是函數 scanf() 的格式化字串要求 %d ,卻輸入其他字元,造成程式發生錯誤,跳過輸入運算符號的部份,結果顯示「輸入錯誤!」。



這是我們對輸入第一個整數進行過的測試,現在我們拿四則運算器的例子重新進行測試,分別輸入 o+o 、 o+9 、 9o9 、 9+o



嗯,前三者都讓 switch 顯示 default 的「輸入錯誤!」,雖然我們希望 switch 的運作是跟輸運運算符號直接相關,不過輸入第一個整數(運算元)時,也導致 switch 選擇 default ,這樣的運作方式倒是可以接受,當成輸入第一個整數的錯誤防範機制。


但是第四個測試卻出現了很奇怪的整數,而且程式能繼續計算,結果還會計算列印出來,這自然不會是我們想要的運作方式,我們總是希望輸入型態不符的話,程式能直接顯示「輸入錯誤!」。類似這樣的錯誤被稱為語意錯誤,就是程式能順利執行,但是結果非預期。


語意錯誤跟語法錯誤都是很常發生的錯誤,後者無法順利編譯,同時編譯器會提供錯誤訊息,然而前者,也就是語意錯誤卻能順利編譯,程式能成功執行,但是會得到非預期的結果。通常語意錯誤需要對程式進行反覆測試,例如在與使用者互動的程式中,利用各種不同的輸入來查看執行結果是否正確。


那我們該如何修正這個錯誤呢?由於函數 scanf() 會回傳一個整數,表示所輸入的型態相符的輸入值。例如要輸入兩個整數,若使用者正確輸入兩個整數, scanf() 就回傳 2 ,同樣的,我們的例子要求輸入一個整數、一個字元及另一個整數,若是依順序輸入型態相符的參數, scanf() 就會回傳整數 3 。


因此我們宣告另一個變數 t 來接收 scanf() 的回傳值,若回傳值不等於 3 ,就把運算符號改為非預期的字元 '!' 。修正後的版本如下
#include <stdio.h>

int main(void)
{
    int a, b, t; //宣告需要用到的變數
    char opt;
    
    printf("這個程式會依符號計算兩個整數的和、差、積、商....\n");
    printf("請輸入計算式,如 2+2: "); //提示使用者輸入的文字
    t = scanf("%d %c %d", &a, &opt, &b);
    
    //如果使用者輸入的除數為 0 ,將除數改為 1
    if (opt == '/' && b == 0) {
        b = 1;
    }
    
    //如果使用者輸入非整數,便將 opt 改成不合法的運算符號
    if (t != 3) {
        opt = '!';
    }
    
    //以下會依運算子計算並印出結果
    printf("結果如下: \n");
    switch (opt) { 
        case '+':
            printf("%d + %d = %d\n", a, b, a + b);
            break;

        case '-':
            printf("%d - %d = %d\n", a, b, a - b);
            break;

        case '*':
            printf("%d * %d = %d\n", a, b, a * b);
            break;

        case '/':
            printf("%d / %d = %d\n", a, b, a / b);
            break;

        default:
            printf("輸入錯誤!\n");
            break;
    }
    
    return 0;
}

/* 《程式語言教學誌》的範例程式
    http://pydoing.blogspot.com/
    檔名:calculator4.c
    功能:接受使用者輸入的四則運算器
    作者:張凱慶
    時間:西元2010年7月 */


程式改變就是多宣告變數 t ,第 11 行變數 t 接受函數 scanf() 的參數
t = scanf("%d %c %d", &a, &opt, &b);


然後第 19 行到第 21 行,檢查 t 是否不等於 3 ,若真就將 opt 設為 '!'
//如果使用者輸入非整數,便將 opt 改成不合法的運算符號
if (t != 3) {
    opt = '!';
}


重新編譯來測試看看吧!



嗯,目前看來,的確解決了輸入型態不符的錯誤。


問題與討論
  1. 為什麼要對程式進行不同輸入值的測試?
  2. 除了這個例子所提的語意錯誤,還有可能有怎樣的語意錯誤呢?
  3. 還有沒有其他防範機制呢?
  4. 如果都改成輸入字元,需要數字再把字元轉換成整數,這樣的作法好不好?




沒有留言: