scanf(“%s",)与gets()输入字符串的区别,以及与getchar()吸收回车键的搭配

来源:互联网 发布:c语言杨辉三角六种 编辑:程序博客网 时间:2024/04/20 11:08

scanf,gets,getchar的区别

三者都是从标准输入流stdio (标准输入设备,一般指向键盘)中读取内容。
1.scanf输入字符串的时候不会接收Space空格,回车EnterTab键,则认为输入结束。
2.gets能接收空格键,回车键,Tab键,回车则认为输入结束
3.getchar只能接受一个字符,遇到回车结束输入,可接受回车键。常用来吸收回车符。

输入操作原理

 程序的输入都建有一个缓冲区,即输入缓冲区。一次输入过程是这样的,当一次键盘输入结束时会将输入的数据存入输入缓冲区,而cin函数,scanf函数直接从输入缓冲区中取数据。正因为cin函数,scanf函数是直接从缓冲区取数据的,所以有时候当缓冲区中有残留数据时,cin函数,scanf函数会直接取得这些残留数据而不会请求键盘输入,这就是有时自己写的代码中为什么会出现输入语句失效的原因!因为scanf()getchar()函数是从输入流缓冲区中读取值的,而并非从键盘(也就是终端)缓冲区读取。而读 取时遇到回车(\n)而结束的,这个\n会一起读入输入流缓冲区的,所以第一次接受输入时取走字符后会留下字符\n,这样第二次的读入函数直接从缓冲区中 把\n取走了,显然读取成功了,所以不会再从终端读取!这就是为什么这个程序只执行了一次输入操作就结束的原因!
例子:
#include<stdio.h>int main(void){int a=0,b=0,c=0,ret=0;ret=scanf("%d%d%d",&a,&b,&c);printf("第一次读入数量:%d\n",ret);ret=scanf("%d%d%d",&a,&b,&c);printf("第二次读入数量:%d\n",ret);return 0;}
我们定义了a,b,c三个变量来接受输入的内容,定义了变量ret来接收scanf函数的返回值。正确输入的话:

 
但是当输入内容与格式换字符串不匹配时,结果会令人大跌眼镜(仔细分析会对scanf函数和stdin流有更深入的哦):

      执行到第一个scanf时,当输入字符’b’的时候与ret=scanf("%d%d%d",&a,&b,&c);中的格式化字符串不匹配,stdin流被阻塞,scanf函数不在读取后面的部分,直接将1返回,表示只将stdin流中的1读入到了变量a中。
      执行到第二个scanf时,字符’b’还是与格式化字符串不匹配,stdin流仍然被阻塞,所以没有提示输入,scanf函数将0返回。
将代码作如下修改,可以有力的证明上述结论。
#include<stdio.h>int main(void){int a=0,b=0,c=0,ret=0;ret=scanf("%d%d%d",&a,&b,&c);printf("第一次读入数量:%d\n",ret);ret=scanf("%c%d%d",&a,&b,&c);printf("第二次读入数量:%d\n",ret);return 0;}
当把第二个scanf函数内的格式化字符串改为”%c%d%d”时,运行结果如下:


执行到第一个scanf函数时,由于输入’b’的原因scanf函数直接返回1,stdin流阻塞。
执行到第二个scanf函数时,字符’b’与格式化字符串”%c%d%d”中的%c匹配,stdin流终于疏通,在输入6,则将变量a,b,c分别赋值为98(‘b’的ASCII码)、2、6,scanf函数返回3。

不同的输入函数是否会舍弃最后的回车符问题

向缓冲区读取字符时
1.scanf()用%c,%s空格键,Tab键,回车键结束一次输入,不会舍弃最后的回车符或空格或Tab(即还在缓冲区中),可使用getchar来吸收scanf()执行之后的换行符。
2.getchar()以回车键结束,也不会舍弃回车符(即存入缓存区)
3.gets()以换行符结束,但之后会舍弃换行符并以'\0',代替(意思是'\n'不会被代入到字符数组中,也不会将换行符存入到缓存区)也就是说:gets()函数读取到\n(我们输入的回车)于是停止读取,但是它不会把\n包含到字符串里面去。然而,和它配合使用的puts函数,却在输出字符串的时候自动换行。
例:
题目描述
在魔法世界,人们的身份证号是一个12位长的数字串。如果足够优秀,人们还可以申请加入魔法工会。如果加入成功,将拥有一个工号。假设所有的工号都是是 6+身份证号的后5位,比如身份证号码为410888845678的魔法师,对应的短号就是645678
现在,如果给你一个12位长的身份证号码,你能找出对应的工号吗?

输入
输入数据的第一行是一个N(N <= 200),表示有N个数据,接下来的N行每一行为一个12位的身份证号码。
输出
输出应包括N行,每行包括一个对应的工号,输出应与输入的顺序一致。
样例输入
2
410888345678
410999454321
样例输出
645678
654321
代码一
#include<stdio.h> int main(){int t;char s[12];scanf("%d",&t);while(t--){getchar();scanf("%s",s);s[6]='6';for(int i=6;i<12;i++)printf("%c",s[i]);printf("\n");}return 0;}


在输入2后回车,进入while循环,此时换行符还在输入缓冲区,然后getchar()吸收换行符,再进行第一次字符串s的输入,回车输入完成,换行符留在输入缓冲区,输出第一次结果,进行第二次循环,此时的getchar()吸收的是上一次滞留在缓冲区的换行符,然后第二次进行字符串s的输入,回车完成,输出第二次的结果,程序执行完毕。

代码二

#include<stdio.h> int main(){int t;char s[12];scanf("%d",&t);while(t--){getchar();gets(s);s[6]='6';for(int i=6;i<12;i++)printf("%c",s[i]);printf("\n");}return 0;}



这个程序与上个唯一不同在于使用gets()输入字符串s.第一次getchar()吸收的是输入2后的换行符,然后第一次输入s的值,回车输入完成(此时的换行符不保留在缓冲区),输出第一次结果,进入第二次循环,缓冲区里并没有什么字符了,此时输入4被getchar()吸收,而10999454321被赋予s,以至于第二次输出结果与代码1不同。