使用C語言怎樣清空輸入緩衝區?這裡有多種方法值得借鑒

來源:互聯網
上載者:User
C語言中有幾個基本輸入函數:

//擷取字元系列
int fgetc(FILE *stream);
int getc(FILE *stream);
int getchar(void);
//擷取行系列
char *fgets(char * restrict s, int n, FILE * restrict stream);
char *gets(char *s);//可能導致溢出,用fgets代替之。
//格式化輸入系列
int fscanf(FILE * restrict stream, const char * restrict format, …);
int scanf(const char * restrict format, …);
int sscanf(const char * restrict str, const char * restrict format, …);

這裡僅討論輸入函數在標準輸入(stdin)情況下的使用。縱觀上述各輸入函數,

  • 擷取字元系列的的前三個函數fgetc、getc、getchar。以getchar為例,將在stdin緩衝區為空白時,等待輸入,直到斷行符號換行時函數返回。若stdin緩衝區不為空白,getchar直接返回。getchar返回時從緩衝區中取出一個字元,並將其轉換為int,返回此int值。

MINGW 4.4.3中FILE結構體源碼

  _iobuf
{
char*_ptr;//指向當前緩衝區讀取位置
int_cnt;//緩衝區中剩餘資料長度
char*_base;
int_flag;
int_file;
int_charbuf;
int_bufsiz;
char*_tmpfname;
} FILE;

各編譯器實現可能不一樣,這裡擷取字元系列函數只用到_ptr和_cnt。

MINGW 4.4.3中getchar()實現

__CRT_INLINE int __cdecl __MINGW_NOTHROW getchar (void)
{
  return (--stdin->_cnt >= 0)
    ?  (int) (unsigned char) *stdin->_ptr++
    : _filbuf (stdin);
}

其中stdin為FILE指標類型,在MINGW 4.4.3中,getc()和getchar()實現為內嵌函式,fgetc()實現為函數。順便說一句,C99標準中已經加入對內嵌函式的支援了。

  • 擷取行系列的fgets和gets,其中由於gets無法確定緩衝區大小,常導致溢出情況,這裡不推薦也不討論gets函數。對於fgets函數,每次敲入斷行符號,fgets即返回。fgets成功返回時,將輸入緩衝區中的資料連分行符號’\n’一起拷貝到第一個參數所指向的空間中。若輸入資料超過緩衝區長度,fgets會截取資料到前n-1(n為fgets第二個參數,為第一個參數指向空間的長度),然後在末尾加入’\n’。因此fgets是安全的。通常用fgets(buf, BUF_LEN, stdin);代替gets(buf);。

  • 格式化輸入系列中,fscanf從檔案流進行格式化輸入很不好用。常用的還是scanf,格式化輸入系列函數捨去輸入資料(根據函數不同可能是標準輸入也可能是字串輸入,如:sscanf)前的空白字元(空格、定位字元、分行符號)直至遇到非空白字元,然後根據格式參數嘗試對非空白字元及後續字元進行解析。該系列函數返回成功解析賦值的變數數,若遇檔案尾或錯誤,返回EOF。

=================分 割 線=================

提到緩衝區,就不得不提setbufsetvbuf兩個緩衝區設定函數,其聲明如下:

 setbuf(FILE * restrict stream,  * restrict buf);
int setvbuf(FILE * restrict stream, char * restrict buf, int mode, size_t size);

setvbuf的mode參數有:

  • _IOFBF(滿緩衝):緩衝區空時讀入資料;緩衝區滿時向流寫入資料。

  • _IOLBF(行緩衝):每次從流讀入一行資料或向流寫入資料。如:stdio,stdout

  • _IONBF(無緩衝):直接從流讀入資料,或者直接向流寫入資料,而沒有緩衝區。如:stderr

setbuf(stream, buf);在:

  • buf == NULL:等價於(void)setvbuf(stream, NULL, _IONBF, 0);

  • buf指向長度為BUFSIZ的緩衝區:等價於(void)setvbuf(stream, buf, _IOFBF, BUFSIZ);

註:BUFSIZ宏在stdio.h中定義。

這裡還要提一下傳說中的setbuf經典錯誤,在《C陷阱和缺陷》上有提到:

 main()
{
    int c;
    char buf[BUFSIZ];

    setbuf(stdout,buf);
    while((c = getchar()) != EOF)
        putchar(c);
    
    return 0;
}

問題是這樣的:程式交回控制給作業系統之前C運行庫必須進行清理工作,其中一部分是重新整理輸出緩衝,但是此時main函數已經運行完畢,buf緩衝區範圍在main函數中,此時buf字元數組已經釋放,導致輸出詭異亂碼。

解決方案:可以將buf設定為static,或者全域變數,或者調用malloc來動態申請記憶體。

=================分 割 線=================

下面來看看幾種流行的緩衝區清空方法:

  • fflush(stdin);式

由C99標準文檔中:

If stream points to an output stream or an update stream in which the most recent
operation was not input, the fflush function causes any unwritten data for that stream
to be delivered to the host environment to be written to the file; otherwise, the behavior is
undefined.

可以看出fflush對輸入資料流為參數的行為並未定義。但由MSDN上的fflush定義:

If the file associated with stream is open for output, fflush writes to that file the
contents of the buffer associated with the stream. If the stream is open for input,
fflush clears the contents of the buffer.

可以看出fflush(stdin)在VC上還是有效地!鑒於各編譯器對fflush的未定義行為實現不一樣,不推薦使用fflush(stdin)重新整理輸入緩衝區。

  • setbuf(stdin, NULL);式

由前面對setbuf函數的介紹,可以得知,setbuf(stdin, NULL);是使stdin輸入資料流由預設緩衝區轉為無緩衝區。都沒有緩衝區了,當然緩衝區資料殘留問題會解決。但這並不是我們想要的。

  • scanf("%*[^\n]");式(《C語言程式設計 現代方法 第二版》中提到)

這裡用到了scanf格式化符中的“*”,即賦值屏蔽;“%[^集合]”,匹配不在集合中的任一字元序列。這也帶來個問題,緩衝區中的分行符號’\n’會留下來,需要額外操作來單獨丟棄分行符號。

  • 經典式

 c;
while((c = getchar()) != '\n' && c != EOF);

由代碼知,不停地使用getchar()擷取緩衝區中字元,直到擷取的字元c是分行符號’\n’或者是檔案結尾符EOF為止。這個方法可以完美清除輸入緩衝區,並且具備可移植性。

相關文章:

禁止頁面緩衝的方法 多語言下禁止頁面緩衝

如何批量清理系統臨時檔案(語言:C#、 C/C++、 php 、python 、java )

相關視頻:

C 語言教程

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.