2010-11-14 37 views
4

此代碼請求數據的用戶,並且隨後的數:如何防止用戶輸入比最大限制更多的數據?

$ cat read.c 
#include<stdio.h> 
#include<stdlib.h> 
#define MAX 10 

int main() { 
    char* c = (char*) malloc(MAX * sizeof(char)); 
    int num; 

    printf("Enter data (max: %d chars):\n", MAX); 
    fgets(c, MAX, stdin); 
    // how do I discard all that is there on STDIN here? 

    printf("Enter num:\n"); 
    scanf("%d", &num); 

    printf("data: %s", c); 
    printf("num: %d\n", num); 
} 
$ 

的問題是,除了,指出字符的最大數目的指示,沒有什麼進入更停止用戶,這是隨後讀入num爲垃圾:

$ ./read 
Enter data (max 10 chars): 
lazer 
Enter num: 
5 
data: lazer 
num: 5 
$ ./read 
Enter data (max 10 chars): 
lazerprofile 
Enter num: 
data: lazerprofnum: 134514043 
$ 

有沒有辦法放棄所有這些都是那裏的fgets電話後STDIN

回答

5

的scanf()的功能是可怕的用戶輸入,並且它不是偉大的文件輸入除非你知道你的輸入數據是正確的(不要那麼信任!)另外,你應該總是檢查fgets()的返回值,因爲NULL表示EOF或其他異常。請記住,除非達到最大值,否則在fgets()數據的末尾會得到用戶的換行符。我可以這樣做第一遍:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#define MAX 10 

void eat_extra(void) { 
    int ch; 

    // Eat characters until we get the newline 
    while ((ch = getchar()) != '\n') { 
     if (ch < 0) 
      exit(EXIT_FAILURE); // EOF! 
    } 
} 

int main() { 
    char c[MAX+1]; // The +1 is for the null terminator 
    char n[16]; // Arbitrary maximum number length is 15 plus null terminator 
    int num; 

    printf("Enter data (max: %d chars):\n", MAX); 
    if (fgets(c, MAX, stdin)) { // Only proceed if we actually got input 
     // Did we get the newline? 
     if (NULL == strchr(c, '\n')) 
      eat_extra(); // You could just exit with "Too much data!" here too 

     printf("Enter num:\n"); 
     if (fgets(n, sizeof(n) - 1, stdin)) { 
      num = atoi(n); // You could also use sscanf() here 
      printf("data: %s", c); 
      printf("num: %d\n", num); 
     } 
    } 

    return 0; 
} 
+0

悲傷但真實。修! – spstanley 2010-11-14 15:40:46

+0

這樣比較好。 '-1'刪除 – pmg 2010-11-14 15:50:17

+0

它應該是'fgets(c,MAX + 1,stdin)'而不是'MAX'。和'fgets(n,sizeof(n),stdin)'而不是'sizeof(n) - 1'。閱讀'fgets'的手冊 – user102008 2010-12-22 00:20:30

-1

我會讀取數據,然後檢查是否有用戶錯誤:

bool var = true; 
while var { 
printf("Enter data (max: %d chars):\n", MAX); 
fgets(c, MAX, stdin); 
// how do I discard all that is there on STDIN here? 
if(strlen(c) <= 10) 
var = false; 
else 
printf("Too long, try again! "); 
} 

在另一方面,如果你不希望這樣做,只是讀NUM兩次,棄去第一個。

+0

-1後'與fgets(C,MAX,標準輸入);', 'strlen(c)'**總是**小於MAX。 – pmg 2010-11-14 15:20:45

5

據我所知,唯一的便攜式解決方案是將自己耗盡緩衝區:

while (getchar() != EOF); 

注意fflush(stdin);not the answer

編輯:如果你只是想丟棄的字符,直到下一個換行符,你可以這樣做:

int ch; 
while ((ch = getchar()) != '\n' && ch != EOF); 
+0

絕對愛你的答案。但是我遇到了一個問題,fgets要求我在超大字符串中輸入兩次。它只是掛在那裏等待另一個進入媒體。任何想法爲什麼?再次感謝 – 2016-09-13 22:53:38

1

什麼「可能發生」fgets

  1. 它返回NULL當在輸入錯誤
  2. 它返回NULL當它發現之前的任何「真實」字符
  3. 它的指針返回到緩衝器
    1. 緩衝WASN一個EOF完全填充
    2. 緩衝區被完全填滿,但輸入中沒有更多數據
    3. 緩衝區被完全填滿ND存在輸入

你怎麼能12區分更多的數據?
feof

你怎麼能3.1.3.2.3.3.
區分通過確定終止空字節和換行寫:
如果輸出緩衝器具有'\n'那麼就沒有更多的數據(緩衝區可能已被完全填充)
如果沒有'\n''\0'位於緩衝區的最後位置,那麼您知道有更多數據在等待;如果位於緩衝區的最後一個位置之前,則在不以換行符結束的流中點擊了EOF

這樣

/* fgets fun */ 
/* 
char buf[SOMEVALUE_LARGERTHAN_1]; 
size_t buflen; 
*/ 
if (fgets(buf, sizeof buf, stdin)) { 
    buflen = strlen(buf); 
    if (buflen) { 
     if (buf[buflen - 1] == '\n') { 
      puts("no more data (3.1. or 3.2.)"); /* normal situation */ 
     } else { 
      if (buflen + 1 == sizeof buf) { 
       puts("more data waiting (3.3.)"); /* long input line */ 
      } else { 
       puts("EOF reached before line break (3.1.)"); /* shouldn't happen */ 
      } 
     } 
    } else { 
     puts("EOF reached before line break (3.1.)"); /* shouldn't happen */ 
    } 
} else { 
    if (feof(stdin)) { 
     puts("EOF reached (2.)"); /* normal situation */ 
    } else { 
     puts("error in input (1.)"); 
    } 
} 

通常的,不完整的測試,是buf[buflen - 1] == '\n'和檢查fgets返回值...

while (fgets(buf, sizeof buf, stdin)) { 
    if (buf[strlen(buf) - 1] != '\n') /* deal with extra input */; 
} 
相關問題