输入缓冲区

文章目录

  • 1. 什么是输入缓冲区
  • 2. scanf("%s",str)从输入缓冲区中获取数据
  • 3. 清理缓冲区
  • 4.scanf函数的知识拓展

1. 什么是输入缓冲区


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

输入缓冲区_第1张图片

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


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


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

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

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

#include 
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;
}

这是大多数人一开始想出来的逻辑,结果怎么样呢:
输入缓冲区_第2张图片

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

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

输入缓冲区_第4张图片

那这里我们在scanf("%c", &input);之前加上一个getchar() 将\n读取了以后,还会不会这样呢?
输入缓冲区_第5张图片

输入缓冲区_第6张图片

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

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

输入缓冲区_第7张图片


3. 清理缓冲区


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

输入缓冲区_第8张图片

注:这里可以这样分析

输入缓冲区_第9张图片
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 
#include 
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只是我们举的一个场景,来更方便我们理解输入缓冲区,具体分析上面有说到。

输入缓冲区_第10张图片


4.scanf函数的知识拓展


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

  1. scanf("%[^\n]"),这里^表示“非”的意思,[^\n]表示读取换行符之前的所有数据(包括空格,注:其中换行符还留在输入缓冲区),[^#]就是读取#前面的所有数据(包括空格,换行符,注:其中#还留在输入缓冲区),我们可以测试一下:
#include 
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.#

输入缓冲区_第11张图片

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

  1. scanf("%*[^\n]%*c),这里*表示该输入项读入后不赋予任何变量,即scanf("%*[^\n]%*c)可以用来表示跳过一行字符串(前面的%*[^\n]可以将\n之前的数据全部读取但不赋予任何变量,后面的%*c可以将回车读取,但不赋予任何变量),如:
#include 
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

输入缓冲区_第12张图片

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

你可能感兴趣的:(c语言)