如何防止用户输入超过最大限制的数据?

时间:2010-11-14 14:39:06

标签: c stdin flush fgets

此代码向用户询问数据,然后询问数字:

$ 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 个答案:

答案 0 :(得分:5)

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

while (getchar() != EOF);

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

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

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

答案 1 :(得分: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;
}

答案 2 :(得分:1)

fgets会发生什么?

  1. 当输入错误时返回NULL
  2. 在任何“真实”字符
  3. 之前找到NULL时会返回EOF
  4. 它返回指向缓冲区的指针
    1. 缓冲区未完全填满
    2. 缓冲区已完全填满,但输入中没有更多数据
    3. 缓冲区已完全填满,输入中有更多数据
  5. 如何区分12
    feof

    如何区分3.1.3.2.3.3.
    通过确定写入终止空字节和换行符的位置:
    如果输出缓冲区有'\n'则没有更多数据(缓冲区可能已被完全填充) 如果没有'\n' AND '\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 */;
    }
    

答案 3 :(得分:-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两次并丢弃第一个。

相关问题