欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

浅谈 scanf(),gets() 区别

程序员文章站 2022-05-08 14:33:11
...

在平时编程过程中,常常会遇到一些莫名其妙的区别。就像下面两张图一样。
浅谈 scanf(),gets() 区别
浅谈 scanf(),gets() 区别
这两张图我们只是简单地输入了几个数据,但是结果发现有个输入中间有空格,但有个没有。这主要是 scanf("%s",ch); 和 gets(ch); 之间的区别。

在最开始先列一下我们要讨论的几种类型。

scanf("%d",&xxx); // 从输入缓冲区第一个非空白符读取,读到下一个非数字字符
scanf("%c",&xxx); // 从输入缓冲区读取第一个字符,不管是不是空白符
scanf("%s",xxx); // 从输入缓冲区第一个非空白符读取,读到下一个空白符
gets(xxx); // 从输入缓冲区第一个字符读取,读到换行符为止

我们在谈论这些之前,先初步了解一下输入缓冲区。
先上个链接 缓冲区
在上面的链接中谈到了缓冲区分为几种类型,我们在这里输入的是行缓冲。当输入遇到换行时才进行操作。比如下面这个例子。

#include<stdio.h>
int main()
{
        int a[5],i;
        for(i=0;i<5;i++){
                scanf("%d",&a[i]);
                printf("%d ",a[i]);
        }
        return 0;
}

这是一个很简单的例子,但有一点特殊的地方。在代码里我输入一个数之后立马就将那个数输出了,但是我运行的时候并不是这样。
浅谈 scanf(),gets() 区别
这是我用空格分开输入时的输出状态。它等到我全部都输入完之后才输出。而我换一种方式输入就不一样。
浅谈 scanf(),gets() 区别
当我每输入一个数之后我是用换行符将他们分割时,每输入一个紧接着就会输出一个数。

为什么会有这种效果呢,就是上面我们所说的 “行缓冲遇到换行时才进行操作”
第一种,我一直是以空格的形式输入的。一开始没输入的时候有个scanf需要数据,他就等着我往输入缓冲区中输入数据。但在没有换行之前它依然没有执行程序,因为我还在往输入缓冲区中输入数据,直到我按下了那个换行符,程序才开始从输入缓冲区中读取数据交给等着要数据的变量。因为我已经把所有数据都送到输入缓存区里了,程序要数据的时候直接从输入缓存区中读取数据即可。所以按下回车之后就将要输出的数据一块输出了。

而第二种不一样。我们是以换行符分割每个输入的,输入 a[0] 后换行,程序就去输入缓存区里读取数据,读完后执行下一个语句,就输出了 a[0] 。接下来也是同样的操作。

到现在为止我们对输入缓冲区有了初步的了解,我们就可以来分析上面那几种类型啦!

第一种: scanf("%d",&xxx);

这里用的是 %d ,%f %ll %lu %l %ld 都是这一种。程序运行到这个输入语句时就去输入缓冲区内找数据。若是缓冲区中没有足够的数据,就会等待你往里面输入数据。
%d 会从第一个非空白符开始读起,读到下一个非数字符。如下面程序。

#include<stdio.h>
int main()
{
        int num,i;
        char ch;
        scanf("%d%c",&num,&ch);
        printf("%d||%c||",num,ch);
        return 0;
}

浅谈 scanf(),gets() 区别
当我们输入一个不太常规的数据时,程序从输入缓冲区中读取数据。遇到空白符跳过,找到第一个数字符开始读取,读到第一个非数字符。所以程序将 2313 送给 num 。送完之后,输入缓冲区中到后面那个3包括他及其之前的数据都被清空了,之后的数据都保留下来了(比如这里的k)。所以紧接着输入 ch 时就将 k 送给 ch。

如果数字接下来是一个空格符也会照样接下。
浅谈 scanf(),gets() 区别
这就是我们接下来要说的 %c 的输入方式。

第二种: scanf("%c",&xxx);

由上面我们已经知道,在输入的数据是 %c 时,不管是不是空白符他都会照接无误。这点 getchar( ); 也是这样。

#include<stdio.h>
int main()
{
        int num,i;
        char ch;
        scanf("%d",&num);
        ch = getchar();
        printf("%d||%c||",num,ch);
        return 0;
}

浅谈 scanf(),gets() 区别
他们就不会像之前那样要等待一个非空白符的出现。不管是什么字符,他们都会读取。

第三种: scanf("%s",xxx);

%s 用于读取一个字符串,它从第一个非空白符读到下一个空白符

#include<stdio.h>
int main()
{
        char ch[20],sh;
        scanf("%s",ch);
        sh = getchar();
        printf("%s||%c||",ch,sh);
        return 0;
}

浅谈 scanf(),gets() 区别
我们在输入字母之前输入了一些空白符,但是 %s 并不会去读取它,他会跳过他们去寻找它的非空白符。要注意的是,它读完字符串后将字符串及其之前的数据全部从输入缓冲区清除后,分割它的空白符并不会从输入缓冲区清除掉。比如这里的空格符,当我们将字符串下一个字符读入到 sh 中发现 sh 存储的是一个空格符,就是分割 %s 的那个空格。这也验证了刚刚说的不会将空白符清除。

而 gets(); 和他不一样

第四种:gets(xxx);

#include<stdio.h>
int main()
{
        char ch[20],sh;
        gets(ch);
        sh = getchar();
        puts(ch);
        printf("||%c||",sh);
        return 0;
}

浅谈 scanf(),gets() 区别
控制台发生的一切似乎有点奇妙,我们来分析一下。
首先我们在一开始输入了空格符接着输入了一些字母符,然后按回车,程序没反应,我再输入了一个回车就有反应了。
我们在输出字母前输入了些空格符,可以看出 gets 从输入缓冲区中读取数据时不会跳过空格符和制表符,这点和 %s 不一样。
还有一点不一样的是,若是 %s 我们按下回车时程序就会给我们反应,它会将这个回车送给 sh ,但这里显然不一样。我们在按下第一个回车后它并没有反应,因为它读取的数据还不够,还在等我们输入。哪个数据没有被赋值呢? sh 。在这里在按下第一个换行符时 sh 并没有读取它,它读取到了我们按下的第二个换行符,所以输出的时候才会发生两个 || 在不同行的情况,因为他们之间的 sh 是我们第二次输入的那个换行符。
为什么会这样呢?因为 %s 在读取到空白符时将那个空白符返回到了输入缓冲区里,再在那个字符串后自动补上了 ‘\0’ ,而 gets 并没有将换行符送回到输入缓冲区,它直接将换行符 ‘\n’ 转变为 ‘\0’ 添加到了字符串末尾, 所以第一个换行符之后输入缓冲区中没有数据可供 sh 读取的了。

%s 和 gets 在这里有两个不一样:

  1. %s 不会读取最开始的空白符,gets 会。
  2. %s 读取结束后会将空白符送回给输入缓冲区,但是 gets 直接将 ‘\n’ 转换成 ‘\0’ ,不再送回给输入缓冲区。
    当然他们还有别的区别,比如 gets 只有遇到换行符才结束输入, %s 遇到空白符就会。

以上就是这几种输入方式细微的区别啦。欢迎大家指正和补充。