scanf、getchar 和缓冲区在程序中如何执行

scanf、getchar 和缓冲区在程序中如何执行

很多人在写完代码后执行程序时会遇到弹出黑框界面后又迅速消失的现象,解决这种问题的办法就是在代码结束部分加上 system(“pause”);这条语句,或者加上一句getchar();接下来从scanf、getchar、缓冲区来说明原因。


首先,我们引入一个例子:
输入一串字符为密码,如果密码正确,确认密码,如果不正确,放弃确认。
代码如下:

#include<stdio.h>

int main()
{
    char input[20]={0};
    char c;
    printf("请输入密码:\n");
    scanf("%s",input);
    printf("请确认密码(Y/N):\n");
    c=getchar();
    if(c=='Y')
    {
        printf("确认成功\n");
    }
    if(c=='N')
    {
        printf("放弃确认\n");
    }

}

接下来运行程序:
这里写图片描述
可以看到,在还没有确认密码的情况下程序就结束了。究竟是因为什么,下面来说说scanf和getchar是怎么获取字符的。


用户从键盘输入字符,计算机将这些字符信息存入到标准输入缓冲区中,随后scanf和getchar再从缓冲区中拿。
在这个程序中,用户输入密码:sguhiaoso后输入回车键,理论上是把密码放入input数组中,然后执行接下来的确认密码阶段。
实际上计算机并不是这样执行的,用户输入sguhiaoso\n之后计算机将这些字符放在缓冲区中,让scanf和getchar从缓冲区中拿取,实际上在用户输入之前,缓冲区中是没有字符的,scanf看到缓冲区中是空的,就静等缓冲区中的字符出现,再从中拿取,在用户输入sguhiaoso\n之后scanf函数开始从缓冲区中拿,在遇到字符\n时,scanf会以为自己要拿的字符在这里就结束了,所以\n不会被scanf拿走,在执行后面的语句时,\n会被getchar拿走,在后面的语句中c中存放的是字符‘\n’,并没有满足条件,所以不会输出结果。程序结束。
过程如下图所示:
1、用户从键盘输入密码,这些字符被放在缓冲区中:

用户从键盘输入密码
2、scanf以%s(获取字符串)的形式从缓冲区中拿取字符:
这里写图片描述
编译结果如下:
这里写图片描述
由此可以看出scanf读入了sguhiaoso,而剩下了字符’\n’。
3、getchar从缓冲区中拿取字符:
这里写图片描述
此时变量c中存放的是ASCII码值为10的字符’ ‘。
这里写图片描述
这时候程序就不会在确认密码时停下来让用户输入字符,因为这时候已经没有输入函数了。


其实在程序中,scanf函数读取字符时遇到空格、回车就会结束,上面程序是对遇到回车结束的例子,接下来分析在这个密码中加入空格时,scanf和getchar会拿走哪些字符。
在之前的程序中输入密码:nishi shui\n
结果如下:
这里写图片描述
结果同样,程序没有等用户确认密码就结束执行。
按照上面的思路分析,scanf从缓冲区中拿走了nishi,而getchar从缓冲区中拿走了空格’ ‘,后面剩下的字符:shui\n被留在了缓冲区中,由于之后没有输入函数了,所以就不会有函数从缓冲区中将它们拿走。
编译程序来验证一下分析的结果:
这里写图片描述
这里写图片描述
由此可以看出scanf拿走了nishi,getchar拿走了空格’ ‘。


解决上述问题的方法有很多,第一种就是用fflush(stdin);这条语句。这条语句的作用是清空缓冲区中的信息,这条语句用到头文件

#include<stdio.h>
#include<stdlib.h>
int main()
{
    char input[20]={0};
    char c;
    printf("请输入密码:\n");
    scanf("%s",input);
    fflush(stdin);
    printf("请确认密码(Y/N):\n");
    c=getchar();
    if(c=='Y')
    {
        printf("确认成功\n");
    }
    if(c=='N')
    {
        printf("放弃确认\n");
    }
    return 0;
}

运行程序,输入密码:nishi shui\n
结果如下:
这里写图片描述
在这个程序中,scanf拿走了nishi,fflush(stdin);这条语句将后面的字符清空,getchar等待缓冲区新的字符出现,并拿走一个字符,执行下面的程序。
通过编译程序验证上述过程:
这里写图片描述
这里写图片描述
由此可以看出,上述叙述过程正确。


注意:fflush这个函数在vs2015版本之后就不再出现了,没有这个函数了。
所以另一种方法就是将这个函数换成另一种形式出现,可以换成getchar();因为getchar每次只能拿走一个字符,所以如果用户在输入多个空格后结果也会同之前出现的错误结果一样。
这种方法是通过创建一个字符型变量ch,将scanf拿走之后的字符通过while语句一一赋给ch,语句体什么都不执行,直到遇到回车结束循环。
代码如下:

#include<stdio.h>
int main()
{
    char input[20]={0};
    char c;
    char ch;
    printf("请输入密码:\n");
    scanf("%s",input);
    while((ch=getchar())!='\n')
    {
        ;
    }
    printf("请确认密码(Y/N):\n");
    c=getchar();
    if(c=='Y')
    {
        printf("确认成功\n");
    }
    if(c=='N')
    {
        printf("放弃确认\n");
    }
    return 0;
}

程序运行结果如下:
这里写图片描述

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值