gets与scanf函数

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

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

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

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

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

  
  
    
    
    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

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

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

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

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

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

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

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

  
  
    
    
    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

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

如果数字接下来是一个空格符也会照样接下。
在这里插入图片描述
这就是我们接下来要说的 %c 的输入方式。

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

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

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

  
  
    
    
    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

在这里插入图片描述
他们就不会像之前那样要等待一个非空白符的出现。不管是什么字符,他们都会读取。

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

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

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

  
  
    
    
    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

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

而 gets(); 和他不一样

第四种:gets(xxx);

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

  
  
    
    
    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

gets与scanf函数_第3张图片
控制台发生的一切似乎有点奇妙,我们来分析一下。
首先我们在一开始输入了空格符接着输入了一些字母符,然后按回车,程序没反应,我再输入了一个回车就有反应了。
我们在输出字母前输入了些空格符,可以看出 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 遇到空白符就会。

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

你可能感兴趣的:(C的问题,c语言,开发语言)