VC 6 的 conio 和 stdio 函式間有一些合作上的小問題

問題

我們寫程式的時候有時你會希望使用者按下任意按鍵 (不限定是 Enter 按鍵) 以後程式再繼續執行下去,此時沒有辦法用 stdio 裡頭的 scanf, getchar, 或是 gets 函式來完成這個功能,因為 stdio 函式庫提供的函式都有輸入緩衝區 (buffer) 的設計,原本設計的用意是希望 CPU 可以一次處理多個 I/O 的動作, 不需要一個按鍵一個按鍵都中斷 CPU 的工作來處理 I/O, 因此對鍵盤介面來說, stdio 基本的要求是一次處理一整列 (以換行字元為區隔), 如果你用 getchar 函式的話, 你輸入任意按鍵以後必須輸入一個 Enter 程式才有反應。

所以我們在這種情形下通常都會用 conio 裡頭提供的 getch 函式,getch 函式在使用者按下任意按鍵後就把那個按鍵的 ASCII 數值讀入程式中。 程式執行到 getch() 函式呼叫時就會暫停在那個地方等待使用者按鍵

一切都很理想, 可是有的時候我們會遇見下面的程式需求

在 TURBO C 或是 Borland C 環境下這兩個輸入命令會正常地執行, (在 GCC/UNIX 環境下沒有 conio 函式庫,必須用 signal 來實作 getch), 但是在 Visual C 6.0 環境下會遇見一些小困難, 你會發現 gets(); 敘述會讀到剛才 getch(); 應該已經讀走的那個字元, 如果你在出現 "請按任意鍵繼續" 時按下 a 鍵, 在出現 "請輸入姓名:" 時按下 b c d e Enter 按鍵的話, 你會發現 'a' 字元不但出現在 c 變數內, 也出現在你的 buf 陣列變數內; 如果你在出現 "請按任意鍵繼續" 時按下先 Enter 按鍵的話, 你會發現 gets(buf) 完全沒有讀到任何東西 (因為它讀到 Enter 時認為讀到了空字串)。 完整測試程式如下: 大部分的時候你會以為這兩個函式沒有任何問題存在, 例如下面的程式碼就不會遇見類似的問題, 其實這個程式也遇見相同的問題, 在按下任意按鍵的時候 getch() 所讀到的東西, scanf() 又會重複地讀到, 只是如果 getch() 讀到的東西是 white space (空格,TAB,或是 Enter) 時 scanf() 會自動跳過去, 因此如果使用者在出現 "請按任意鍵繼續" 時按下 Enter 按鍵, 程式在執行到 scanf 時會很正常地跳過 Enter, 你可以測試一下如果使用者在出現 "請按任意鍵繼續" 時按下 a 按鍵, 程式在執行到 scanf 時會連這個 a 也一起讀入而造成你不希望得到的結果。

如何克服

1. 換一個 compiler (這個問題還算小,應該沒有必要用那麼激烈的手段)

2. 在 getch 後多呼叫一次 getchar 把那個多餘的按鍵讀掉

Nasty!! is it?

3. 你可以自己去 MSDN Library 中查詢看看有沒有其它的解決方式

C++ 程式設計課程 首頁

製作日期: 3/04/2003 by 丁培毅 (Pei-yih Ting)
E-mail: pyting@cs.ntou.edu.tw TEL: 02 24622192x6615
海洋大學 理工學院 資訊科學系