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

嗯,前三者都讓 switch 顯示 default 的「輸入錯誤!」,雖然我們希望 switch 的運作是跟輸運運算符號直接相關,不過輸入第一個整數(運算元)時,也導致 switch 選擇 default ,這樣的運作方式倒是可以接受,當成輸入第一個整數的錯誤防範機制。
但是第四個測試卻出現了很奇怪的整數,而且程式能繼續計算,結果還會計算列印出來,這自然不會是我們想要的運作方式,我們總是希望輸入型態不符的話,程式能直接顯示「輸入錯誤!」。類似這樣的錯誤被稱為語意錯誤,就是程式能順利執行,但是結果非預期。
語意錯誤跟語法錯誤都是很常發生的錯誤,後者無法順利編譯,同時編譯器會提供錯誤訊息,然而前者,也就是語意錯誤卻能順利編譯,程式能成功執行,但是會得到非預期的結果。通常語意錯誤需要對程式進行反覆測試,例如在與使用者互動的程式中,利用各種不同的輸入來查看執行結果是否正確。
那我們該如何修正這個錯誤呢?由於函數 scanf() 會回傳一個整數,表示所輸入的型態相符的輸入值。例如要輸入兩個整數,若使用者正確輸入兩個整數, scanf() 就回傳 2 ,同樣的,我們的例子要求輸入一個整數、一個字元及另一個整數,若是依順序輸入型態相符的參數, scanf() 就會回傳整數 3 。
因此我們宣告另一個變數 t 來接收 scanf() 的回傳值,若回傳值不等於 3 ,就把運算符號改為非預期的字元 '!' 。修正後的版本如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | #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; } /* 《程式語言教學誌》的範例程式 檔名:calculator4.c 功能:接受使用者輸入的四則運算器 作者:張凱慶 時間:西元2010年7月 */ |
程式改變就是多宣告變數 t ,第 11 行變數 t 接受函數 scanf() 的參數
11 | t = scanf ( "%d %c %d" , &a, &opt, &b); |
然後第 19 行到第 21 行,檢查 t 是否不等於 3 ,若真就將 opt 設為 '!'
18 19 20 21 | //如果使用者輸入非整數,便將 opt 改成不合法的運算符號 if (t != 3) { opt = '!' ; } |
重新編譯來測試看看吧!

嗯,目前看來,的確解決了輸入型態不符的錯誤。
問題與討論
- 為什麼要對程式進行不同輸入值的測試?
- 除了這個例子所提的語意錯誤,還有可能有怎樣的語意錯誤呢?
- 還有沒有其他防範機制呢?
- 如果都改成輸入字元,需要數字再把字元轉換成整數,這樣的作法好不好?
沒有留言:
張貼留言