当scanf EOF循环行为异常时 [英] While scanf EOF loop misbehaving

查看:105
本文介绍了当scanf EOF循环行为异常时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是C语言的初学者,但遇到了无法解决的问题,也无法在此处找到其他线程的解决方案。

I'm a beginner in C, and I've got problem I can't figure out, and wasn't able to find a solution on other threads here.

我正在尝试使用以下代码从键盘输入/ txt文件中读取整数:

I'm trying to read integers from a keyboard input/ txt file with the following code:

int grades[MAX_GRADES_LENGTH]={0}, histogram[HISTOGRAM_SIZE]={0};
int maxGradesHistogramBucket=0, median=0, gradesLength=0;
double avg=0.0;
int grade=0;

printf("Enter grades:\n");
while (scanf("%d",&grade) != EOF)
{
    grades[gradesLength]=grade;
   gradesLength=gradesLength+1;
}

我应该在grades []数组中设置这些成绩并计算循环中数组的长度。

I'm supposed to set these "grades" in the grades[] array and count the length of the array along the loop.

不知何故,循环的行为不正常,似乎有些输入可以使用循环,但是对于某些输入(大多数他们实际上)scanf()不能获得EOF,无论它是文件的实际结尾还是终端中的^ D命令。

Somehow the loop is misbehaving, it seems that some inputs are ok with the loop, but for some inputs(most of them actually) the scanf() doesn't get the EOF, whether it's an actual end of file, or the ^D command in the terminal.

scanf()并不是读取数据的最可靠方法,但是不幸的是,由于我们在课堂上还没有学过任何其他方法,因此我无法使用其他任何东西,因此我们只能在作业中使用scanf()。

I've heard the scanf() is not the most reliable method to read data, but unfortunately I can't use anything else since we haven't learned any other method in class so we can only use scanf() on our homework.

我试图用 == 1 != EOF

I've tried to change the!= EOF with == 1 and its all the same.

作为输入


100 0 90 10 80 20 70 30 60 40 50

100 0 90 10 80 20 70 30 60 40 50

例如,它可以正常工作。
,但要输入:

for example it works fine. but for the input:


0 50 100

0 50 100

循环是无限的。

我正在使用macbook pro btw(如果有关系)。

I'm using a macbook pro btw (if it matters).

有什么想法吗?

推荐答案

如果键入字母而不是数字,则 scanf()将返回0(如零成功转换的数字)而不是EOF(如无数据可读取)。正确的测试是确保您获得了预期的值数-在这种情况下,为1:

If you type a letter instead of a number, scanf() will return 0 (as in, "zero successfully converted numbers") and not EOF (as in, "there was no data left to read"). The correct test is to ensure that you got the expected number of values — in this case, 1:

while (scanf("%d", &grade) == 1)

如果您需要知道是否EOF或没有结果(但是读取其余行可能会解决问题),然后从 scanf()

If you need to know whether you got to EOF or got no result (but reading the rest of the line might clear the problem), then capture the return value from scanf():

int rc;
while ((rc = scanf("%d", &grade)) == 1)
{
}
if (rc != EOF)
    …read the rest of the line, or at least the next character, before resuming the loop…

,如果您确实愿意,则可以这样写:

And, if you really want to, you could then write:

int rc;
while ((rc = scanf("%d", &grade)) != EOF)
{
    if (rc == 1)
        grades[gradesLength++] = grade;
    else
    {
        printf("Discarding junk: ");
        int c;
        while ((c = getchar()) != EOF && c != '\n')
            putchar(c);
        putchar('\n');
        if (c == EOF)
            break;
    }
}

else中的代码子句可以合理地放在函数中。它还可能会将消息报告为标准错误而不是标准输出。让用户知道您反对的内容是有礼貌的。您可以在换行符之前使用其他测试来停止(&&!isdigit(c)&& c!='+'&& c!='-',使用< ctypes.h> 中的 isdigit())。但是,用户没有机会重新编辑他们放在字母后面的内容,因此您可能会误解他们的输入内容。最好扔掉其余的输入行,然后让它们重新开始。

The code in the else clause could plausibly be put into a function. It might also report the messages to standard error rather than standard output. It is courteous to let the user know what it was that you objected to. You could stop before newline with a different test (&& !isdigit(c) && c != '+' && c != '-', using isdigit() from <ctypes.h>). However, the user doesn't have a chance to re-edit the stuff they put after the letters, so you may be going to misinterpret their input. It is probably better just to throw away the rest of the line of input and let them start over again.

As < a href = https://stackoverflow.com/users/2410359/chux> chux 已注意到,在读取可能是整数一部分的字符后,需要将该字符放回输入流中。因此,如果我要分析该行的其余部分并重新开始扫描实际上可能是整数一部分的第一个数据,我会考虑使用类似以下内容的东西:

As chux noted, after reading a character that could be part of an integer, that character needs to be put back into the input stream. Therefore, if I were going to analyze the rest of the line and restart scanning at the first data that could actually be part of an integer, I'd consider using something like:

#include <ctype.h>

static inline int could_be_integer(int c)
{
    return isdigit(c) || c == '+' || c == '-');
}

,然后else子句可能是:

and then the else clause might be:

else
{
    printf("Discarding junk: ");
    int c;
    while ((c = getchar()) != EOF && c != '\n' && !could_be_integer(c))
        putchar(c);
    putchar('\n');
    if (could_be_integer(c))
        ungetc(c, stdin);
    else if (c == EOF)
        break;
}

如您所见,这太混乱了。有时(如天气变化评论),使用 fgets(),然后循环使用 sscanf()(请参阅如何使用 sscanf()循环?)。注意关于使用 fflush(stdin) 的建议;它并不是到处都会自动出错,但是在正常情况下它不会在MacBook Pro上运行。

This gets messy, as you can see. Sometimes (as Weather Vane noted in a comment), it is easier to read a line with fgets() and then use sscanf() in a loop (see How to use sscanf() in a loop?). Be wary of suggestions about Using fflush(stdin); it isn't automatically wrong everywhere, but it won't work on a MacBook Pro under normal circumstances.

总体上,只是忽略了其余的输入行通常是更好的界面决策。

On the whole, simply ignoring the rest of the line of input is usually a better interface decision.

这篇关于当scanf EOF循环行为异常时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆