C语言 Scanf 和循环

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3852789/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 06:36:20  来源:igfitidea点击:

Scanf and loops

cscanf

提问by Danny

here a a piece of code that is supposed to loop over and over until the user inputs a number between 0 and 15

这里是一段代码,它应该一遍又一遍地循环,直到用户输入 0 到 15 之间的数字

        int input;

        do
        {

                printf("Enter a number => ");
                scanf("%d",&input);
                printf("\n %d \n",input);

        }
        while (!(input>0 && input <15));

However if the user puts in something like "gfggdf" it results in the loop repeating over and over and over and never prompting the user for input again... the console looks like this

但是,如果用户输入诸如“gfggdf”之类的内容,则会导致循环一遍又一遍地重复,并且不再提示用户输入......控制台看起来像这样

Enter a number =>
0
Enter a number =>
0
Enter a number =>
0
Enter a number =>
0
Enter a number =>
0
Enter a number =>
0
(looping indefinitely)

After looking through this book, it seems I need to do something like this to prevent this from happening.

看完这本书后,似乎我需要做这样的事情来防止这种情况发生。

int input, error, status;
char skip_ch;

do
{
        error = 0;

        printf("Enter a number => ");
        status = scanf("%d",&input);
        printf("\n %d \n",input);

        if(status!=1)
        {
                error=1;
        }
        else if(input < 0 || input >15){
                error = 1;
        }

        do
        {
                scanf("%c",&skip_ch);
        }while(skip_ch != '\n');
}
while (error);

I understand needing to check for the scanf status to make sure it was valid input, What I don't understand the the inner do-while loop. I feel like the book never really explained to me why scanf needs to be called several times like that, it's like somehow the scanf buffer got filled up with a bunch of garbage and it's somehow cleaning it out by just looping through it a million times for you.

我明白需要检查 scanf 状态以确保它是有效输入,我不明白内部 do-while 循环。我觉得这本书从来没有真正向我解释过为什么需要像这样多次调用 scanf,就好像 scanf 缓冲区被一堆垃圾填满了,它以某种方式通过循环一百万次来清除它你。

Could anyone please explain this black magic to me?

谁能给我解释一下这个黑魔法?

回答by Jonathan Leffler

That's why there are so many answers to similar questions that recommend not using scanf().

这就是为什么有很多类似问题的答案建议不要使用scanf().

Also, you should check the return value from scanf()because it tells you when something has gone wrong - and no value could be converted.

此外,您应该检查 from 的返回值,scanf()因为它会告诉您何时出现问题 - 并且无法转换任何值。

The normal recommended solution is a combination of fgets()to read lines of input and sscanf()to parse the line once it is read.

通常推荐的解决方案是fgets()读取输入sscanf()行并在读取后解析该行的组合。

The second loop in your example goes around reading the characters up to and including a newline, thus resynchronizing scanf()and skipping any bogus data. It is a long-winded way of doing it; it would be simpler to use getchar()instead:

您示例中的第二个循环围绕读取字符直到并包括换行符,从而重新同步scanf()和跳过任何虚假数据。这是一种冗长的方法。使用它会更简单getchar()

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

Note the use of 'int c;' - the type is crucially not 'char' or 'unsigned char' because it must store all possible charvalues plus EOF.

请注意“ int c;”的使用- 类型关键不是“ char”或“ unsigned char”,因为它必须存储所有可能的char值加上 EOF。

回答by Jerry Coffin

The original code loops indefinitely because the invalid data (the "gfggdf") is notremoved from the input buffer when scanf fails to convert it to an integer -- it's left in the input buffer, so the next call to scanf looks at the same data, and (of course) still can't convert it to an integer, so the loop executes yet again, and the results still haven't changed.

原始代码无限循环,因为当 scanf 未能将其转换为整数时,无效数据(“gfggdf”)不会从输入缓冲区中删除 - 它留在输入缓冲区中,因此对 scanf 的下一次调用看起来相同数据,并且(当然)仍然无法将其转换为整数,因此循环再次执行,结果仍然没有改变。

The:

这:

do {
        scanf("%c",&skip_ch);
}while(skip_ch != '\n');

simply reads one character at a time (and ignores it) until it gets to the end of the line. If you prefer to get rid of the garbage in the input buffer without a loop, you can use something like: scanf("%*[^\n]");

一次只读取一个字符(并忽略它),直到它到达行尾。如果您更喜欢在没有循环的情况下清除输入缓冲区中的垃圾,您可以使用以下内容:scanf("%*[^\n]");

Another possibility that's (probably more) widely used is to start by reading an entire line, then attempting to convert what's in the line. Whether it converts or not, you've already read all the data to the end of the line so the next attempt at reading/converting will start from the next line whether the conversion worked or not. This does have one potential weakness: if you got a really longline of input, you could end up reading and storing a lot of data for which you have no real use. It's rarely a big deal, but you should still be aware of it.

另一种(可能更广泛)广泛使用的可能性是首先阅读整行,然后尝试转换行中的内容。无论转换与否,您都已将所有数据读到行尾,因此无论转换是否成功,下一次读取/转换尝试都将从下一行开始。这确实有一个潜在的弱点:如果你有很的输入行,你最终可能会读取和存储大量实际上没有用的数据。这很少有什么大不了的,但你仍然应该意识到这一点。

回答by Ruel

First of all, avoid using scanf(), use fgets()instead.

首先,避免使用scanf()fgets()而是使用。

To evaluate your condition (first code). 0 > 0is false. 0 < 15is true. false && trueis false. !falseis true. That's why it's looping indefinitely.

评估您的状况(第一个代码)。0 > 0false0 < 15truefalse && truefalse!falsetrue。这就是它无限循环的原因。