简体   繁体   English

Scanf和循环

[英]Scanf and loops

here aa 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. 我理解需要检查scanf状态以确保它是有效输入,我不理解内部do-while循环。 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,就像扫描缓冲区填充了一堆垃圾一样,它只是通过循环遍历它一百万次来清理它您。

Could anyone please explain this black magic to me? 有人可以向我解释这个黑魔法吗?

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. 此外,您应该检查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. 示例中的第二个循环用于读取字符,包括换行符,从而重新同步scanf()并跳过任何虚假数据。 It is a long-winded way of doing it; 这是一种冗长的做法; it would be simpler to use getchar() instead: 使用getchar()会更简单:

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

Note the use of ' int c; 注意使用' int c; ' - the type is crucially not ' char ' or ' unsigned char ' because it must store all possible char values plus EOF. ' - 类型关键不是' char '或' unsigned char ',因为它必须存储所有可能的char值加EOF。

The original code loops indefinitely because the invalid data (the "gfggdf") is not removed 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. 原代码循环下去,因为无效的数据(以下简称“gfggdf”) 从输入缓冲区中取出时scanf函数无法将其转换为整数-它留在输入缓冲器,因此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 long line 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. 这很少是一件大事,但你仍应该意识到这一点。

First of all, avoid using scanf() , use fgets() instead. 首先,避免使用scanf() ,而是使用fgets()

To evaluate your condition (first code). 评估您的情况(第一个代码)。 0 > 0 is false . 0 > 0false 0 < 15 is true . 0 < 15true false && true is false . false && truefalse !false is true . !falsetrue That's why it's looping indefinitely. 这就是它无限循环的原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM