注册 登录
编程论坛 C语言论坛

请问这个scanf为什么不能输入?

B_bang 发布于 2018-06-21 22:41, 5290 次点击
#include<stdio.h>
#include<ctype.h>

int main(void)
{
    double value = 0.0;
    double sum = 0.0;
    unsigned int count = 0;
    char answer = 0;
   
    for(;;)
    {
        printf("\nEnter a value:");
        scanf("%lf",&value);
        
        sum += value;
        ++count;
        
        printf("\nDo you want countinue. (y or n)?:");
        scanf("%c",&answer);
   
        if('n' == tolower(answer))
            break;
    }
   
    printf("\nyou have input %d number ,and the average of these number is %.2lf",count,sum/count);
   
    return 0;
}


程序如上,其中scanf("%c",&answer);这句,程序直接跳过,不需要输入。请问是那里出错了?执行结果如下:
Enter a value:3

Do you want countinue. (y or n)?:
Enter a value:2

Do you want countinue. (y or n)?:
Enter a value:1

Do you want countinue. (y or n)?:
Enter a value:n

Do you want countinue. (y or n)?:
you have input 4 number ,and the average of these number is 1.75请按任意键继续.
. .
8 回复
#2
自学的数学2018-06-21 22:52
这里是需要输入字母 y 和 n,根据输入的字母(不是数字)来决定要执行的操作。
#3
书生牛犊2018-06-21 22:59

程序代码:
int main(void)
{
    double value = 0.0;
    double sum = 0.0;
    unsigned int count = 0;
    char answer = 0;
   
    for(;;)
    {
        printf("\nEnter a value:");
        scanf("%lf",&value);//程序读完这个%lf,赋值给value以后,缓冲区会保留有一个你敲进去的回车
        
        sum += value;
        ++count;

        printf("\nDo you want countinue. (y or n)?:");
//解决方法就是在scanf(%c)的前面加一个清空缓冲区语句fflush(stdin);或者像这种你明知道应该只有1个回车符的情形就可以用一个getchar()把那个缓冲区里的回车读掉。下一个getchar()或者canf(%c)就能读到你真正想要的y or n 了。
        scanf("%c",&answer);//程序在scanf(%c)  或者getchar() 的时候不会自动跳过缓冲区的空白符{如:回车换行制表符空格tab等}。而scanf(%d%f%s)之类的就会自动跳过缓冲区的空白符直到遇到第一个不算空白符的字符就开始读了。
   
        if('n' == tolower(answer))
            break;
    }
   
    printf("\nyou have input %d number ,and the average of these number is %.2lf",count,sum/count);
   
    return 0;


可以参考的资料,请自行搜索“C 清空缓冲区”{有条件使用谷歌之类墙外的引擎自然最好,不行百度也能找得到,就是你需要多翻翻,才能看到真正想看的}

#4
lin51616782018-06-21 23:28
回复 3楼 书生牛犊
前面的输入有字符滞留缓冲区影响后面的输入 这一段是对的
用fflush(stdin)清理缓冲区 这一段是错的
fflush函数 操作的是输出流
stdin是输入流 用fflush操作输入流是什么效果不确定
#5
lin51616782018-06-21 23:29
最简单的修改方式
%c前面加一个空格
        scanf(" %c",&answer);

就可以了
#6
刘浩伟2018-06-22 01:54
#7
B_bang2018-06-22 22:03
感谢,学习了,补充下理论知识。
(以下内容转载自网络)scanf()函数的原理

想象输入设备(键盘)连接着一个叫“缓冲”的东西,把缓冲认为是一个字符数组。

当你的程序执行到scanf时,会从你的缓冲区读东西,如果缓冲区是空的,就阻塞住,等待你从键盘输入。

现在假设你的缓冲区里有:abcd\n1234\n  (其中\n是回车符)执行:scanf("%s",name);的时候,由于scanf是读数据直到看见空白符(空白符:指空格符、制表符、回车符)就停止的输入函数。所以执行后,把abcd存到了name中。缓冲区于是变成了 : \n1234\n

接下来的执行就有问题了,如果遇到了:scanf("%d",&number);怎么办?因为遇到了回车符,它并不是一个数字,所以scanf还有一个特性,就是忽略先导的空白符。不管是有几百个回车也好,几万个空格也罢,只要它们连续地出现在缓冲区的开头,就统统忽略他们。然后再读有意义的字符。于是1234被读入number。

回到刚刚,当缓冲区还是:\n1234\n的时候,如果遇到了:scanf("%c",&sex);应该怎么办呢?你说,那好办呀,不是说了忽略前导空白符吗?跳过回车读'1'呀!想法是好的,可这只针对你的程序这一种情况。如果我编写的程序就是统计用户输入了多少个回车呢?所以对scanf来讲跳过前导空白符有个例外,当参数是%c的时候,就把缓冲区的第一个字符返回回去,不管是什么。

这样的设计就有个问题,scanf对不同的参数表现出来的特性不一样。得承认,这是个缺陷,但不是说这样不好。

这样的设计至少把发现所有字符的机会交给了用户,设计者这样想:如果程序员使用了scanf("%c",..),那他就有必要知道这函数能把回车符读出来,至于程序员对回车符感不感兴趣,那就看他了,不感兴趣的话,程序员也一定知道该怎么处理。回到你的程序里。

当执行scanf("%s",name)的时候,要求你从键盘输入,于是你输入了"abc",然后“回车”。缓冲区里自然而然地是:abc\nscanf把abc拿走了,留下了\n,缓冲区里现在就剩下\n于是,下一个scanf ("%c",&sex); 想当然地读取了\n

- 关于scanf忽略前导空白符这一点,可以这样验证:

写个程序,用scanf()读数据,只要不是%c就行。然后输入的时候,随便输入回车、空格、制表符,然后“回车”确认。会发现程序依然提示等待你输入。就是因为它忽略掉所有前导空白符之后发现缓冲区是空的!于是乖乖地阻塞住,等待你输入。

- 关于scanf是直到看见空白符结束读取这一点,如果你是初学C的话,那么很快你就会遇到另一个函数,叫gets()。

程序里如果我们想一次读入一个英文句子:I am a student.如果你用scanf读的话,只能读出"I",想读出后面的东西要不断调scanf。此时需要用gets,这个函数不管是什么一律读进来,直到遇到回车符才停下。总之,各有各的用途,全都熟悉之后,才能在恰当的时候恰当地使用
#8
lin51616782018-06-22 23:40
回复 7楼 B_bang
%[] 了解一下
#9
li19932018-06-23 10:44
了解了解
1