2014-06-06 109 views
1

我一直在想辦法清除scanf函數中的錯誤條目,以允許循環提示執行其工作。當輸入無效時清除scanf緩衝區的好方法

我在這裏有一個函數調用刷新輸入。這種方法可行,但如果我要求int時輸入類似2q的東西,它仍然很麻煩。

void flushKeyBoard() 
{ 
    int ch; //variable to read data into 
    while((ch = getc(stdin)) != EOF && ch != '\n'); 
} 

然後我會在另一個功能是這樣的:

printf("Enter a value: "); 
check = scanf("%f", &b); 

while(check == 0) 
{ 
    printf("Invalid number entered. Please re-enter: "); 
    check = scanf("%f, &b"); 
    flushKeyBoard(); 
} 

更好的想法?有人建議fflush();但它不是真正的標準,這裏使用..

+0

閱讀C-faq問題[12.26a](http://www.c-faq.com/stdio/stdinflush.html)和[12.26b](http://www.c-faq.com) /stdio/stdinflush2.html)。 – haccks

+0

你現有的'flushKeyBoard'看起來不錯,你到底有什麼問題? –

+0

無論您想將「2q」視爲一個有效的int並放棄「q」,或者如果您想放棄整行,都必須在執行'scanf'的代碼片段中控制。如果你想考慮「2q」是一個錯誤(而不是讀「2」,然後丟棄q)你可以更新'flushKeyboard'來返回'bool'來表明它是否真的清除了某些東西。 –

回答

3

使用getchar(常見的,容易理解的)

int c; 

while ((c = getchar()) != EOF && c != '\n'); /* <note the semicolon! */ 

if (c == EOF) { 
    if (feof(stdin)) { 
     /* Handle stdin EOF. */ 
    } 
    else { 
     /* Handle stdin error. */ 
    } 
} 

使用fgets(不太常見,少可理解)

char buf[8]; 

while (fgets(buf, sizeof buf, stdin) != NULL) { 
    size_t len = strlen(buf); 

    /* 
    * Exit the loop if either EOF was encountered before '\n', or 
    * if '\n' is detected. 
    */ 
    if (len + 1 != sizeof(buf) || memchr(buf, '\n', len)) 
     break; 
} 

if (feof(stdin)) { 
    /* Handle stdin EOF. */ 
} 
else { 
    /* Handle stdin error. */ 
} 

使用具有scanf一個掃描集(可能是不常見的,易於理解)

/* 
* Combining the scanset with assignment suppression (the '*' before the 
* scanset) will return EOF on EOF/error and 0 if '\n' was read. 
*/ 
if (scanf("%*[^\n]") == EOF) { 
    if (feof(stdin)) { 
     // Handle stdin EOF. 
    } 
    else { 
     // Handle stdin error. 
    } 
} 
getchar(); // Flush the '\n'. 

使用getline(可能是罕見的,困難)

char *buf = NULL; 
size_t bufsize = 0; 
ssize_t len; 

/* getline() will stop reading on '\n' or EOF. */ 
len = getline(&buf, &bufsize, stdin); 

/* No bytes read and EOF encountered, or there was an error. */ 
if (len == -1) { 
    if (feof(stdin)) { 
     /* Handle stdin EOF. */ 
    } 
    else if (ferror(stdin)) { 
     /* Handle stdin error. */ 
    } 
    else { 
     /* Handle errno error, if desired. */ 
    } 
    /* 
    * The value of "buf" is indeterminate here, so you likely 
    * just want to return from the function/program at this point 
    * rather than continuing and potentially freeing an invalid 
    * buffer. 
    */ 
} 
free(buf); 

當然,所有的這些方法都假定要處理的事情上EOF /錯誤發生不同於與\n ,甚至所有三個都是單獨的案例。例如,通過將上面的片斷之一到一個獨立的功能,你可以,如果\n讀取或錯誤EOF上EOF /錯誤,或\n甚至0EOF對EOF,並返回10

事情值得注意:

  • getcharfgets方法是100%跨平臺的。我更喜歡getchar方法的簡單性。
  • 由於並非所有編譯器都實現掃描集(因此不符合C99標準),所以scanset方法不太適合跨平臺。
  • getline方法也不是十分跨平臺的:它主要在GNU/Linux和其他一些POSIX操作系統上實現;這個時候不包括Windows。一旦你有一些管理內存和使用指針的經驗,寫一個自己並不難,但你最好使用前兩種方法之一,因爲編寫getline的實現可能最終會使用fgetcfgets無論如何(fgetc(stdin)getchar()應該表現相同)。
0

您可以使用:

fscanf(stdin, "%*[^\n]%*c"); 
0

有這樣做的幾種方法。實際上,你正在試圖做的是消費一行文本到一個\ n字符(或EOF)。爲了正確地做到這一點,你應該使用的sscanf(或的fscanf)

sscanf("%*[^\n]\n"); 

此用途正則表達式[^ \ n] * \ n(任意數量的不是\ n的字符,後跟一個\ n)並消耗與之匹配的所有內容。

編輯:因爲我很笨,忘了scanf regex使用的語法略有不同。