输入缓冲区

文章介绍了输入缓冲区的概念,以及在使用scanf函数获取字符串时可能遇到的问题。当用户输入包含空格或回车的字符串时,需要通过getchar或清除缓冲区的方法来避免未预期的行为。文章提供了解决方案,包括使用while循环清除缓冲区,并展示了如何使用scanf的特殊格式匹配字符串。
摘要由CSDN通过智能技术生成

1. 什么是输入缓冲区


输入缓冲区:这是一个我们键盘输入与编译器读取之间的一个缓冲区域,编译器并不是直接读取我们在键盘上输入的信息,而是从输入缓冲区中读取的信息。

在这里插入图片描述

我们使用scanf、getchar等输入函数时,并不是直接从键盘中去获取,而是由键盘打到输入缓冲区中,然后scanf,getchar等输入函数再从输入缓冲区里面去获取数据。


2. scanf(“%s”,str)从输入缓冲区中获取数据


我们在使用scanf函数获取一个字符串时,大多数时候都会遇到一个状况,这里我们举一个输入密码然后登录的例子来看一下。

注:这里补充一个知识点,strcmp()函数,它的头文件是<string.h>,我们比较字符串是否相等,是用它来比较,而不是用 == ,strcmp(str1,str2)括号里面是放两个需要比较的字符串,如果两个字符串相等,则返回0,如果第一个字符串大于第二个字符串,则返回一个大于0的值,如果第一个字符串小于第二个字符串,则返回一个小于0的值。

大致的逻辑是:我们设密码为123456,输入完密码以后,我们还需要确认密码,如果密码正确,则显示登录成功代码如下:

#include <stdio.h>
int main()
{
    char password[20] = { 0 };
    printf("Please input a password :>");
    scanf("%s", password);//输入密码
    char input = 0;
    printf("Please confirm the password(Y/N) :>");
    scanf("%c", &input);//确认或取消密码
    if ('Y' == input)//确认密码
    {
        if (strcmp(password, "123456") == 0)//如果密码为123456,则显示登录成功
            printf("Login succeeded\n");
        else
            printf("Login failed\n");//密码不为123456则显示登录失败
    }
    else//取消确认
        printf("Cancel confirmation\n");
    return 0;
}

这是大多数人一开始想出来的逻辑,结果怎么样呢:
在这里插入图片描述

可以看到,在我们输入完密码之后,还没等我们输入确认或取消(Y/N)就直接显示了登录失败。这个问题应该是怎么解决呢?

在这里插入图片描述
我们输入密码时,是把123456\n输入到输入缓冲区中(\n是回车),然后由scanf去从输入缓冲区中去获取,但我们平常用来输入字符串的scanf(“%s”,str)不会读取回车符和空格符,所以我们第一个scanf("%s", password);只读取了123456,这时候输入缓冲区里面还剩一个\n,导致第二个scanf("%c", &input);把\n读取了,所以就导致了我们还没有输入(Y/N)就直接显示登录失败。

在这里插入图片描述

那这里我们在scanf("%c", &input);之前加上一个getchar() 将\n读取了以后,还会不会这样呢?
在这里插入图片描述

在这里插入图片描述

如图,这样做我们就显示登录成功了,流程就是:

我们先输入一串字符串,随后再用getchar()来清空输入缓冲区中的\n,然后再输入Y\n,就显示登录成功了。注:最后输入缓冲区中还存在一个\n,这是我们输入Y\n后留下的,因为对后续没有什么影响了,所以我们在这里就不用清理了

在这里插入图片描述


3. 清理缓冲区


当然,如果是在这个场景,我们这样处理是没问题的,但如果换一个场景的话,就不行了,假如我们输入密码时:123456 abc\n输入成这个样子(后面会有一些乱七八糟的东西),那这样的话,我们加一个getcaht()也无济于事了(scanf(“%s”,password)只吸收空格前面的内容)。如果不处理掉输入缓冲不过去里面的内容的话,也会发生这样的效果:

在这里插入图片描述

注:这里可以这样分析

在这里插入图片描述
scanf(“%s”,password)读取了空格之前的内容,也就是123456,所以输入缓冲区中还剩 abcd\n,然后我们后面的getchar()也只会读取一个字符,也就是将空格读取了,所以后面的scanf(“%c”,input)就把缓冲区中的a读取了,这样就导致了我们上面出现的错误。

所以,我们应该要先清空输入缓冲区:

while (getchar() != '\n')
{
	;
}

我们可以这样来处理掉缓冲区里面的杂物。

这里while判断的条件是getchar != ‘\n’,getchar读取到哪个字符,它的返回值就是哪个字符,所以,这里我们这样来清空缓冲区,是连带’\n’一起清理掉的(当getchar()吸收了’\n’,则getchar() == ‘\n’ ,不满足条件就退出while循环了)

这样我们就可以把输入缓冲区里面的杂物全都清理掉了。

最终代码写成这样:

#include <stdio.h>
#include <string.h>
int main()
{
    char password[20] = { 0 };
    printf("Please input a password :>");
    scanf("%s", password);//输入密码
    char input = 0;
    //清空输入缓冲区
    while (getchar() != '\n')
    {
        ;
    }
    printf("Please confirm the password(Y/N) :>");
    scanf("%c", &input);//确认或取消密码
    if ('Y' == input)//确认密码
    {
        if (strcmp(password, "123456") == 0)//如果密码为123456,则显示登录成功
            printf("Login succeeded\n");
        else
            printf("Login failed\n");//密码不为123456则显示登录失败
    }
    else//取消确认
        printf("Cancel confirmation\n");
    return 0;
}

这样的话不管我们怎么输入都能够很好的预测scanf()是这样读取数据的了。
注:这里密码依旧是123456,后面的 abcdefg只是我们举的一个场景,来更方便我们理解输入缓冲区,具体分析上面有说到。

在这里插入图片描述


4.scanf函数的知识拓展


之前我们说过,scanf(“%s”,str),只能读取空格或者回车符前面的数据,那如果我们想要用scanf读取这些数据应该怎么办呢?

  1. scanf("%[^\n]"),这里^表示“非”的意思,[^\n]表示读取换行符之前的所有数据(包括空格,注:其中换行符还留在输入缓冲区),[^#]就是读取#前面的所有数据(包括空格,换行符,注:其中#还留在输入缓冲区),我们可以测试一下:
#include <stdio.h>
int main()
{
	char str1[20] = { 0 };
	char str2[20] = { 0 };
	char str3[20] = { 0 };
	scanf("%[^\n]", str1);//这里读取hello world
	scanf("%[^#]", str2);//这里读取了\nhello China\n
	scanf("%s", str3);//这里读取了#
	printf("%s\n", str1);
	printf("%s\n", str2);
	printf("%s\n", str3);
	return 0;
}

输入:

1.Hello world\n
2.Hello China\n#\n
3.Hello

输出:

1.Hello world
2.\nHello China\n
3.#

在这里插入图片描述

注:'\n'就是回车。这里我们在#之后加了一个回车键,所以我们输入的第三条语句(Hello)和#后面的\n还停留在输入缓冲区中

  1. scanf("%*[^\n]%*c),这里*表示该输入项读入后不赋予任何变量,即scanf("%*[^\n]%*c)可以用来表示跳过一行字符串(前面的%*[^\n]可以将\n之前的数据全部读取但不赋予任何变量,后面的%*c可以将回车读取,但不赋予任何变量),如:
#include <stdio.h>
int main()
{
	char str1[20] = { 0 };
	scanf("%*[^\n]%*c");
	scanf("%[^\n]", str1);
	printf("%s",str1);
	return 0;
}

输入:

1.hello world\n
2.hello China\n

输出:

hello China

在这里插入图片描述

注:我们第一行输入的数据都被scanf("%*[^\n]%*c");所读取掉 了,此时输入缓冲区只有一个\n,是来自我们输入的第二行最后输入的’\n’

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hyt的笔记本

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值