C++_Primer中關於cin.clear()的例題

#include<iostream>
#include<limits>
using namespace std;


int main()
{
	int ival;
	while(cin >> ival, !cin.eof())		//必須輸入兩個文件結束符纔可以結束輸入???
	{
		if(cin.bad())		//input stream is corrupted; bail out
			throw runtime_error("IO stream corrupted");
		if(cin.fail())
		{
			cerr << "bad data,   try again   ";		//bad input
			cin.clear();		//warn the user		1
			cin.ignore(numeric_limits<int>::max(), '\n');	//ignore bad input,清空輸入緩衝區的數據
			//也可以是cin.ignore(numeric_limits<streamsize>::max(), '\n');
			//同時上面ignore函數也可以用一個cin.get();代替
			//fflush(stdin);作用也同上,但是它是VC編譯器的擴展功能,並不是C/C++標準裏定義的,所以最好還是不用
			continue;		//get next input
		}
		// ok to process ival
		cout << ival << "\t";
	}
	cout << endl;
	return 0;
}


/*問題:
標號1處:原例題是cin.clear(istream::failbit);但是會出現一旦輸入字符,
就進入死循環的情況,即相當於clear函數沒有執行,clear(flag)不是將制定條
件狀態flag設爲有效嗎??不解

網上查找:WYYZAS的博客

  C/C++ 誤區—— fflush(stdin)

作者:antigloss 
1.       爲什麼fflush(stdin) 是錯的

首先請看以下程序:

程序代碼

#i nclude<stdio.h> 
int main( void )
{
    int i;
    for (;;) {
        fputs("Please input aninteger: ", stdout);
        scanf("%d", &i);
        printf("%d\n", i);
    }
    return 0;
}

這 個程序首先會提示用戶輸入一個整數,然後等待用戶輸入,如果用戶輸入的是整數,程序會輸出剛纔輸入的整數,並且再次提示用戶輸入一個整數,然後等待用戶輸入。但是一旦用戶輸入的不是整數(如小數或者字母),假設 scanf 函數最後一次得到的整數是 2 ,那麼程序會不停地輸出“Please input an integer: 2”。這是因爲   scanf("%d", &i); 只能接受整數,如果用戶輸入了字母,則這個字母會遺留在“輸入緩衝區”中。因爲緩衝中有數據,故而scanf 函數不會等待用戶輸入,直接就去緩衝中讀取,可是緩衝中的卻是字母,這個字母再次被遺留在緩衝中,如此反覆,從而導致不停地輸出“Please input an integer: 2”。

也許有人會說:“居然這樣,那麼在 scanf 函數後面加上‘fflush(stdin);’,把輸入緩衝清空掉不就行了?”然而這是錯的!C和C++的標準裏從來沒有定義過fflush(stdin)。也許有人會說:“可是我用fflush(stdin) 解決了這個問題,你怎麼能說是錯的呢?”的確,某些編譯器(如VC6)支持用 fflush(stdin) 來清空輸入緩衝,但是並非所有編譯器都要支持這個功能(gcc3.2不支持),因爲標準中根本沒有定義 fflush(stdin)。MSDN 文檔裏也清楚地寫着 fflush on input stream is anextension to the C standard (fflush 操作輸入流是對C標準的擴充)。當然,如果你毫不在乎程序的移植性,用  fflush(stdin)也沒什麼大問題。以下是 C99 對 fflush 函數的定義:

int fflush(FILE *stream);

如果stream指向輸出流或者更新流(updatestream),並且這個更新流
最近執行的操作不是輸入,那麼fflush函數將把任何未被寫入的數據寫入stream
指向的文件(如標準輸出文件stdout)。否則,fflush函數的行爲是不確定的。
fflush(NULL)清空所有輸出流和上面提到的更新流。如果發生寫錯誤,fflush
函數會給那些流打上錯誤標記,並且返回EOF,否則返回0。

由此可知,如果 stream 指向輸入流(如 stdin),那麼 fflush 函數的行爲是不確定的。故而使用 fflush(stdin) 是不正確的,至少是移植性不好的。

2.       清空輸入緩衝區的方法

雖然不可以用 fflush(stdin),但是我們可以自己寫代碼來清空輸入緩衝區。只需要在 scanf 函數後面加上幾句簡單的代碼就可以了。

程序代碼

/* C 版本 */
#i nclude<stdio.h>
int main( void )
{
    int i, c;
    for (;;) {
        fputs("Please input aninteger: ", stdout);
        if ( scanf("%d",&i) != EOF ) { /* 如果用戶輸入的不是 EOF */
            /*while循環會把輸入緩衝中的殘留字符清空 */
            /* 讀者可以根據需要把它改成宏或者內聯函數 */
            /* 注:C99中也定義了內聯函數,gcc3.2支持 */
            while ((c=getchar()) != '\n' && c != EOF ) {
                  ;
            } /*end of while */
        }
        printf("%d\n", i);
    }
    return 0;
}

/* C++ 版本 */


#i nclude <iostream>
#i nclude <limits>  // 爲了使用numeric_limits

using std::cout;
using std::endl;
using std::cin;

int main( )
{
       int value; 
       for (;;) {
              cout<< "Enter an integer: ";
              cin>> value;
/* 讀到非法字符後,輸入流將處於出錯狀態,
              * 爲了繼續獲取輸入,首先要調用clear函數
              * 來清除輸入流的錯誤標記,然後才能調用
              * ignore函數來清除輸入緩衝區中的數據。 */          
              cin.clear();
              /*numeric_limits<streamsize>::max( ) 返回緩衝區的大小。
              * ignore 函數在此將把輸入緩衝區中的數據清空。
* 這兩個函數的具體用法請讀者自行查詢。 */
              cin.ignore(std::numeric_limits<std::streamsize>::max( ), '\n' );
              cout<< value << '\n';
       }
       return 0;
}
*/

——桑海整理
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章