C語言-輸入緩衝區(Input Buffer) 
輸入緩衝區(Input buffer)是用來放置使用者輸入的資料,並由一個pointer來控制read/write的位置
這個pointerC語言中稱為File pointer,而在C++稱為get pointer。先看個簡單的範例:
	範例1:
	::::::::::::::::::::::::::::::::::::::::::::::
	#include<stdio.h> 
	int main() 
	{ 
		int num; 
		char chr; 

		printf("Input one int:"); 
		scanf("%d",&num); 
		printf("Input a character:"); 
		scanf(" %c",&chr); 		//注意%c之前有空格
		printf("%d\n%c\n",num,chr); 
		return 0; 
	}  
	:::::::::::::::::::::::::::::::::::::::::::::
	假設輸入100A100A會被放置到輸入緩衝區中,並且搭配著File pointer控制著:
	執行第一個scanf("%d",&num);
	(1)num = 100;
	(2)File pointer移動到下一個位置:
	執行第二個scanf(" %c",&chr);
	(1)chr = 'A';
	(2)File pointer移動到下一個位置:
目前應該對於輸入緩衝區有點感覺了!接著來從錯誤的輸入資料中研究輸入的機制:
	範例2
	::::::::::::::::::::::::::::::::::::::::::::::
	#include<stdio.h> 
	int main()
	{ 
		int num1,num2; 
		char chr; 

		printf("Input two ints:"); 
		scanf("%d %d",&num1,&num2);
	
		printf("Input a character:"); 
		scanf("%c",&chr); 
		printf("%d\n%d\n%c\n",num1,num2,chr); 

		return 0; 
	}
	:::::::::::::::::::::::::::::::::::::::::::::
	輸出(紅色表示輸入的資料)Input two ints:A 100
	Input a character:-858993460
	-858993460
	A
	為什麼輸出的結果是這個樣子呢?說明一下:
	(1)將輸入資料'A'100放置到輸入緩衝區中
	(2)執行scanf("%d %d",&num1,&num2);
	(3)由於scanf第一個輸入格式是整數(%d),與File pointer所指的資料('A')不符,造成輸入錯誤
	   使得scanf無法繼續進行輸入的動作,表示scanf("%c",&chr);無法進行輸入的動作,直到
	   輸入緩衝區中File pointer指向EOF(End-Of-File)或是清空輸入緩衝區
	(4)輸入發生錯誤,使得使用者無法進行程式所指定的輸入,但輸入緩衝區仍會將資料放置到scanf
	    輸入變數中與輸入緩衝區資料相符合的記憶體中:
	  ()緩衝區中的資料有'A'100,而File pointer是指著資料'A'
	   ()執行完第一個scanf(...),緊接著第二個scanf(...),輸入格式與'A'相符,所以將'A'的
	      資料複製到chrFile pointer往下一個位置移動
	(5)因為num1num2並沒有從輸入緩衝區中得到符合的資料而且也沒有給定初始值,所以印出來的值
	   是前次程式執行之所殘留在記憶體內的無效值
如果覺得有點模糊沒有關係,再舉一個範例來說明這個機制:
	範例3
	::::::::::::::::::::::::::::::::::::::::::::::
	#include<stdio.h> 
	int main()
	{ 
		int num1,num2; 
		char chr; 

		printf("Input two ints:"); 
		scanf("%d",&num1);
		scanf("%d",&num2);
		printf("Input a character:"); 
		scanf(" %c %d",&chr,&num2); 
		printf("%d\n%d\n%c\n",num1,num2,chr); 

		return 0; 
	}
	:::::::::::::::::::::::::::::::::::::::::::::
	輸出(紅色表示輸入的資料)Input two ints:100 A
	Input a character:20
	100
	20
	A
	(1)將輸入資料100'A'放置到輸入緩衝區中,File pointer指向資料100的位置
	(2)執行第一個scanf("%d",&num1);,輸入格式是整數(%d),與輸入緩衝區內File pointer所
	   指位置的資料格式相符合,故將100複製給num1,並將File pointer移到下一個位置
	(3)執行第二個 scanf("%d",&num2);,輸入格式是整數(%d),與輸入緩衝區入File pointer所指
	   位置的資料('A')格式不相符合,故輸入產生錯誤,無法執行使用者輸入的動作。
	(4)執行第三個 scanf(" %c %d",&chr,&num2);,第一個輸入格式是字元(%c),與輸入緩衝區內
	   File pointer所指位置的資料('A')格式相符合,故將'A'複製給chr,並將File pointer移到下一個位置
	(5)因為緩衝區內File pointer所指的位置已無資料,此時File pointer指向EOF(End-Of-File),所以輸入
	   的動作復原,scanf(...)可執行使用者輸入的動作,故第三個scanf(...)的第二個輸入格式可以接收使
	   用者的輸入,所以作者輸入20(6)接著將變數內的資料顯示出來。
經過以上的說明相信多多少少能瞭解使用scanf(...),當發生輸入資料格式的錯誤時會發生什麼樣的狀況。
那要如何解決這個問題呢?有兩種方式
(1)把在輸入緩衝區內的資料清除掉,

	利用fflush(stdin); or fflush(NULL); 

(2)把在輸入緩衝區內的資料消化掉,
	char dummy[20];	//數字自己訂!合適就好!
	gets(dummy);
在做數值的輸入時,若寫程式的人沒有注意到接收到錯誤的資料時,容易使程式產生錯誤,這點必須注意。
為了避免以上的錯誤,可以先利用字串的方式接收使用者的輸入資料,然後將每個資料做分解的動作,在依
據資料的格式做分配的動作,以下簡單介紹最後一個範例:
	範例4
	::::::::::::::::::::::::::::::::::::::::::::::
	#include<stdio.h> 
	int main()
	{ 
		int num1,num2; 
		char str[81];

		printf("Input two ints:");
		gets(str);

		if(sscanf(str,"%d%d",&num1,&num2)==2)
			printf("%d,%d\n",num1,num2);
		else
			printf("Input error!!!");
	
		return 0; 	
	}
	::::::::::::::::::::::::::::::::::::::::::::
	sscanf()會傳回多少個 fields被有效scan,可以判斷輸入是否符合格式。
接下來介紹容易有問題的程式:
      ::::::::::::::::::::::::::::::::::::::::::::
      
  #include<stdio.h>
             #include<stdlib.h>
             int main()
            {
               int num;
               char ch;

               while(1)
               {
                   printf("Please input number:");
                   scanf("%d",&num);

                   printf("Continue...(Y/N)?");
                   scanf("%c",&ch);
                   if( tolower(ch)=='n')
                       break;
                }
   
                return 0;
             }
              ::::::::::::::::::::::::::::::::::::::::::::
	執行結果(藍色字為輸入的部份):
	Please input number:1
	Continue...(Y/N)?Please input number:n
	Continue...(Y/N)?

問題來了,為什麼會是這樣的顯示結果呢?
因為在輸入1的同時,按下Enter鍵之後,真正在輸入緩衝區中的資料是數值1'\r'(Enter鍵的ASCII代碼)
1num變數給接收了!而接下來的'\r'character,所以直接給ch做為輸入資料
這就導致為什麼scanf("%c",&ch);沒有在畫面中產生作用的原因。
等'\r'被接收之後,迴圈再執行一次,而輸入'n'時,因為與scanf("%d",&num);中整數格式不符合
所以不做接收的動作,等到第二個scanf("%c",&ch);'n'是字元的型態,所以儲存至ch變數中。
也就因此離開迴圈!
解決辦法,有兩種:
(1)"%c"中,%c前面空一格==>" %c"
(2)scanf("%d",&num);底下加上fflush(stdin); 

那為什麼(1)中加空格就行了呢?
加了空格表示接收非空格型態的資料,空格型態包括Enter鍵、Tab鍵、空白鍵
可以參考書籍的介紹!
有二個不錯的的函式可以學學,在此推薦給各位:
	sscanf();
	sprintf();

Written By James On 2003/10/07
Hosted by www.Geocities.ws

1