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
$ 

有没有办法STDIN在通话后丢弃所有内容fgets

4

4 回答 4

5

The scanf() function is terrible for user input, and it's not that great for file input unless you somehow know your input data is correct (don't be that trusting!) Plus, you should always check the return value for fgets() since NULL indicates EOF or some other exception. Keep in mind that you get the user's newline character at the end of your fgets() data unless the maximum is reached first. I might do it this way as a first pass:

#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;
}
于 2010-11-14T15:11:08.030 回答
5

据我所知,唯一可移植的解决方案是自己耗尽缓冲区:

while (getchar() != EOF);

请注意,这fflush(stdin);不是答案

编辑:如果您只想丢弃字符直到下一个换行符,您可以执行以下操作:

int ch;
while ((ch = getchar()) != '\n' && ch != EOF);
于 2010-11-14T14:54:01.017 回答
1

什么“可能发生” fgets

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

如何区分12
feof

如何区分3.1.和通过确定终止空字节3.2.3.3.
换行符的写入位置:
如果输出缓冲区有 a'\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 */;
}
于 2010-11-14T16:20:37.480 回答
-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 两次并丢弃第一个。

于 2010-11-14T14:49:04.873 回答