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() 函式呼叫時就會暫停在那個地方等待使用者按鍵
....
printf("Please enter any key to continue...");
getch();
....
一切都很理想,
可是有的時候我們會遇見下面的程式需求
int c;
char buf[80];
....
printf("請按任意鍵繼續...");
c=getch();
....
printf("請輸入姓名:");
gets(buf);
....
在 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
時認為讀到了空字串)。
完整測試程式如下:
#include
#include
void main()
{
int c;
char buf[80];
printf("請按任意鍵繼續...");
c=getch();
printf("請輸入姓名:");
gets(buf);
printf("c=[%c], buf=[%s]\n", c, buf);
}
大部分的時候你會以為這兩個函式沒有任何問題存在,
例如下面的程式碼就不會遇見類似的問題,
#include
#include
void main()
{
int c;
char buf[80];
printf("請按任意鍵繼續...");
c=getch();
printf("請輸入姓名:");
scanf("%s", buf);
printf("c=[%c], buf=[%s]\n", c, buf);
}
其實這個程式也遇見相同的問題,
在按下任意按鍵的時候 getch() 所讀到的東西,
scanf() 又會重複地讀到,
只是如果 getch() 讀到的東西是 white space (空格,TAB,或是 Enter)
時 scanf() 會自動跳過去,
因此如果使用者在出現 "請按任意鍵繼續" 時按下 Enter 按鍵,
程式在執行到 scanf 時會很正常地跳過 Enter,
你可以測試一下如果使用者在出現 "請按任意鍵繼續" 時按下 a 按鍵,
程式在執行到 scanf 時會連這個 a 也一起讀入而造成你不希望得到的結果。
如何克服
1. 換一個 compiler (這個問題還算小,應該沒有必要用那麼激烈的手段)
2. 在 getch 後多呼叫一次 getchar 把那個多餘的按鍵讀掉
#include
#include
void main()
{
int c;
char buf[80];
printf("請按任意鍵繼續...");
c=getch();
printf("請輸入姓名:");
getchar()
gets(buf);
printf("c=[%c], buf=[%s]\n", c, buf);
}
Nasty!! is it?
3. 你可以自己去 MSDN Library 中查詢看看有沒有其它的解決方式