浅谈 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需要数据,他就等着我往输入缓冲区中输入数据。但在没有换行之前它依然没有执行程序,因为我还在往输入缓冲区中输入数据,直到我按下了那个换行符,程序才开始从输入缓冲区中读取数据交给等着要数据的变量。因为我已经把所有数据都送到输入缓存区里了,程序要数据的时候直接从输入缓存区中读取数据即可。所以按下回车之后就将要输出的数据一块输出了。
而第二种不一样。我们是以换行符分割每个输入的,输入 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;
}
当我们输入一个不太常规的数据时,程序从输入缓冲区中读取数据。遇到空白符跳过,找到第一个数字符开始读取,读到第一个非数字符。所以程序将 2313 送给 num 。送完之后,输入缓冲区中到后面那个3包括他及其之前的数据都被清空了,之后的数据都保留下来了(比如这里的k)。所以紧接着输入 ch 时就将 k 送给 ch。
如果数字接下来是一个空格符也会照样接下。
这就是我们接下来要说的 %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("%s",xxx);
%s 用于读取一个字符串,它从第一个非空白符读到下一个空白符。
#include<stdio.h>
int main()
{
char ch[20],sh;
scanf("%s",ch);
sh = getchar();
printf("%s||%c||",ch,sh);
return 0;
}
我们在输入字母之前输入了一些空白符,但是 %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;
}
控制台发生的一切似乎有点奇妙,我们来分析一下。
首先我们在一开始输入了空格符接着输入了一些字母符,然后按回车,程序没反应,我再输入了一个回车就有反应了。
我们在输出字母前输入了些空格符,可以看出 gets 从输入缓冲区中读取数据时不会跳过空格符和制表符,这点和 %s 不一样。
还有一点不一样的是,若是 %s 我们按下回车时程序就会给我们反应,它会将这个回车送给 sh ,但这里显然不一样。我们在按下第一个回车后它并没有反应,因为它读取的数据还不够,还在等我们输入。哪个数据没有被赋值呢? sh 。在这里在按下第一个换行符时 sh 并没有读取它,它读取到了我们按下的第二个换行符,所以输出的时候才会发生两个 || 在不同行的情况,因为他们之间的 sh 是我们第二次输入的那个换行符。
为什么会这样呢?因为 %s 在读取到空白符时将那个空白符返回到了输入缓冲区里,再在那个字符串后自动补上了 ‘\0’ ,而 gets 并没有将换行符送回到输入缓冲区,它直接将换行符 ‘\n’ 转变为 ‘\0’ 添加到了字符串末尾, 所以第一个换行符之后输入缓冲区中没有数据可供 sh 读取的了。
%s 和 gets 在这里有两个不一样:
- %s 不会读取最开始的空白符,gets 会。
- %s 读取结束后会将空白符送回给输入缓冲区,但是 gets 直接将 ‘\n’ 转换成 ‘\0’ ,不再送回给输入缓冲区。
当然他们还有别的区别,比如 gets 只有遇到换行符才结束输入, %s 遇到空白符就会。
以上就是这几种输入方式细微的区别啦。欢迎大家指正和补充。
上一篇: C语言学习——数组详解
下一篇: C语言学习——指针详解
推荐阅读
-
浅谈href=#与href=javascript:void(0)的区别
-
oracle中left join和right join的区别浅谈
-
浅谈MySQL和MariaDB区别(mariadb和mysql的性能比较)
-
gets() 与 scanf() 的小尴尬
-
浅谈Pandas中map, applymap and apply的区别
-
浅谈js使用in和hasOwnProperty获取对象属性的区别
-
浅谈COOKIE和SESSION区别
-
C语言——常用标准输入输出函数 scanf(), printf(), gets(), puts(), getchar(), putchar(); 字符串拷贝函数 strcpy(), strncpy(), strchr(), strstr()函数用法特点
-
浅谈apache和nginx的rewrite的区别
-
浅谈PHP中单引号和双引号到底有啥区别呢?