C 清空輸入緩衝區,以及fflush(stdin)的使用誤區和解決方案,fflushstdin

來源:互聯網
上載者:User

C 清空輸入緩衝區,以及fflush(stdin)的使用誤區和解決方案,fflushstdin

對C 語言初學者來說,fflush(stdin)函數被解釋為會清空輸入緩衝區的一個系統函數,這是一個曾經幾乎對過一半的說法,隨著電腦科學的進步,在學習的過程中的逐步完善,將fflush(stdin)函數的過去與現在分析一下。

Personal thinking:

fflush(stdin) 會清空輸入緩衝區中的內容,讀取時輸入緩衝區中的內容會被scanf函數逐個取走,正常case下scanf()函數可以根據傳回值判斷成功取走的數目;當發生異常讀取的時候,如應該讀取一個整形,結果輸入緩衝區內當前的內容是個字串,發生讀取異常。發生讀取異常之後,輸入緩衝區中的內容並未被取走,那麼下次迴圈之時,scanf()函數發現輸入緩衝區中有內容(顯然編譯器不會關心這個內容是不是合法),於是不再等待user輸入,直接嘗試讀取輸入緩衝區中的內容,顯而易見的又是一次讀取異常,如此反覆。

include <stdio.h>int main( void ){    int val,ret;    while(fflush(stdin),(ret = scanf("%d",&val)) != EOF)         printf(“%d\n”, val);    return 0;}

按照直覺,這個程式使用了fflush(stdin)以確保讀取異常時不干涉下一次的讀取。那麼問題來了,事實果真如此嗎?

fflush(stdin)的前世今生
由Microsoft官方提供的MSDN 文檔裡也清楚地寫著:fflush on input stream is an extension to the C standard(fflush 操作輸入資料流是對 C 標準的擴充,注意啊,是Extension!)。即C 標準中根本沒有定義 fflush(stdin),最新的C 11直接刪去了曾經打擦邊球的fflush(stdin)。
這也就是開頭說的fflush(stdin)曾經幾乎對過一半的原因:fflush()確實也是擴充,這就是幾乎對過的意思,在vs 2013之前的版本裡,包括 vc++ 6.0 fflush(stdin)也確實管用。現在即使在vs 2015環境下fflush(stdin)也不再起作用,遑論lunix系統下呢,這就是曾經對一半。
當然,如果毫不在乎程式的移植性,在可用 fflush(stdin)的版本裡面這麼寫也沒什麼大問題。

清空輸入緩衝區的可替代方法

既然fflush(stdin)現在在vs 2015 下不幹活了,那麼總得有接替背鍋的角色,實現清空緩衝區的角色,下面根據查閱的結果,給出兩種在C 可以實現清空輸入緩衝區功能的可行方案。
首先聲明下,使用setbuf(stdin,NULL)是GCC下可用的一種方法,但是沒有解決掉緩衝的問題,然而這裡不予深究。
在vs 2015 下,可以用下面兩種方法代替fflush(stdin)實現功能:
1)使用函數rewind(stdin)
從函數名上來看,這個函數應該是重定義了輸入緩衝區的Location or Size,用這個方法得到新緩衝區,前後兩個輸入緩衝區並不是一樣的(純猜測,輕點打臉!),其實這個函數好像也是非標準定義的(不是很確定,因為在 C 11與 C 99 的 更新裡面真沒看到這個,不過也可以作為暫時管用的半個。都說到這裡,多說一句,C 11 標準確實地刪除了gets()函數,用gets_s()代替,關於這一點放在最後一個連結內)

2)使用scanf(“%*[^\n]%*c”),原理是用掃描集將緩衝區中的字元全部讀取來實現清除輸入緩衝區的動作,就效果來說非常管用,而且還跨平台。
乍一看這東西還有點深奧,給出詳細的解釋,也可以參考連結裡面的解釋說明。
對scanf(“%*[^\n]%*c”)解釋:
%〔^\n〕將逐個讀取緩衝區中的’\n’字元之前的其它字元,%後面的表示將讀取的這些字元丟棄,前遇到’\n’字元時便停止讀取操作,此時,緩衝區中尚有一個’\n’字元遺留,所以後面的%*c將讀取並丟棄這個遺留的分行符號,這裡的星號和前面的星號作用相同。由於所有從鍵盤的輸入都是以斷行符號結束的,而斷行符號會產生一個’\n’字元,所以將’\n’連同它之前的字元全部讀取並丟棄之後,也就相當於清除了輸入緩衝區。

關於fflush(stdout)

如果不考慮fflush(stdin)這個坑的話,它的兄弟fflush(stdout)還是有很大的作用的,簡言之,fflush(stdout)強制輸出當前輸出緩衝區中的內容,一些在Debug下一些莫名其妙的error可以用fflush(stdout)立即輸出在處理過程中的中間結果來確定error所在。
在查閱過程中發現一句話:
fflush(stdin)對輸入資料流的操作是未定義的,所以這個還是要慎用,或許有副作用。
fflush(stdout)只是將需要輸出的輸出緩衝區中內容當即輸出,利於調試且沒有什麼不良後果。

不管怎麼說,向當年的二極體一樣,fflush(stdin)也在電腦的發展過程中廣泛使用過,時過境遷。一回首已百年身,也許以後的學習過程中再也不會遇見fflush(stdin)了。

文章來源:http://blog.csdn.net/veniversum/article/details/62048870

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.