代码之家  ›  专栏  ›  技术社区  ›  Aakash Goel

如何防止用户输入比最大极限更多的数据?

  •  4
  • Aakash Goel  · 技术社区  · 14 年前

    此代码要求用户提供数据,然后是一个数字:

    $ 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
    $ 
    

    有没有办法把上面的东西都扔掉 STDIN 之后 fgets 打电话?

    4 回复  |  直到 14 年前
        1
  •  5
  •   spstanley    14 年前

    scanf()函数对于用户输入是很糟糕的,除非你知道你的输入数据是正确的(不要那么信任!)另外,应该始终检查fgets()的返回值,因为NULL表示EOF或其他异常。记住,除非首先达到最大值,否则在FGSH()数据的末尾得到用户的换行符。我可以这样做作为第一步:

    #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;
    }
    
        2
  •  5
  •   Frédéric Hamidi    11 年前

    据我所知,唯一的便携式解决方案是自己耗尽缓冲器:

    while (getchar() != EOF);
    

    请注意 fflush(stdin); not the answer .

    编辑: 如果只想在下一个换行符之前放弃字符,可以执行以下操作:

    int ch;
    while ((ch = getchar()) != '\n' && ch != EOF);
    
        3
  •  1
  •   pmg    14 年前

    会发生什么 fgets ?

    1. 它又回来了 NULL 当输入有错误时
    2. 它又回来了 无效的 当它发现 EOF 在任何“真实”角色之前
    3. 它返回指向缓冲区的指针
      1. 缓冲区没有完全填满
      2. 缓冲区已完全填满,但输入中没有更多数据
      3. 缓冲区已完全填满,输入中有更多数据

    你怎么能区分 1 2 ?
    具有 feof

    你怎么能区分 3.1. , 3.2. 3.3.
    通过确定终止空字节和换行符的写入位置:
    如果输出缓冲区有 '\n' 则不再有数据(缓冲区可能已完全填满)
    如果没有 '\n' 以及 这个 '\0' 是在缓冲区的最后一个位置,那么您知道还有更多的数据在等待;如果 '\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 */;
    }
    
        4
  •  -1
  •   J V    14 年前

    我会读取数据,然后检查是否存在用户错误:

    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并丢弃第一个。