用scanf同时输入不同类型的成员数据常常会出现意想不到的情况,这是为啥呢?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用scanf同时输入不同类型的成员数据常常会出现意想不到的情况,这是为啥呢?相关的知识,希望对你有一定的参考价值。
scanf会读取之前input buff里的空格。与getchar等混用容易出现问题。要么统一全用scanf,要么用getchar()吃掉空格,回车。
其实用c++的cin就好了嘛。 参考技术A scanf函数原理:
scanf中scan是扫描之意。控制台有个输入缓冲区,用户输入的所有数据首先被送到缓冲区缓存着。用户每次敲击键盘,都将数据(包括空白符)送到输入缓冲区。当输入Enter时,scanf就从这缓冲区取数据。
(ps:以上为我以前所做笔记)
(ps:以下为网上的,删改较多,由参考资料所提供网址参考)
用scanf输入时,输入流的结尾必有回车字符'\n'(因为必定要按回车键),这个字会被其后的getch()和getchar()直接读入。
解决方法:清空输入流,在每次scanf后面加上一个语句fflush(stdin);
而且,若之前的输入流中也含有回车符,也会造成类似问题。
解决方法:若要scanf在输入前忽略所有空白字符(\n,\t,空格),可在%s和%c前面加上一个空格,变成scanf(" c",&s);
未雨绸缪:
对于输入字符的,不使用%c而使用%s,因为%c是不忽略空白字符的而%s忽略。可把char s;改为char s[2];,然后scanf("%c", &s);改为scanf("%1s", s);。%1s表示只读一个字符到字符串。
参考资料:http://zhidao.baidu.com/question/155323636.html
本回答被提问者采纳scanf()函数分析
首先,先来讲一下scanf的读取流程:
从键盘输入的都是字符类型(一系列的字符),scanf()的作用就是将这个字符序列转换成一个或多个指定的类型,并保存到变量中。
从键盘输入的字符序列会先缓存到键盘缓冲区中,当用户输入回车,这时会清空键盘缓冲区,将键盘缓冲区的数据(包括回车)送入到stdin中
这时scanf()开始从stdin中读取数据。
scanf()在读取每个字段时都会忽略空白符(%c比较特殊)。以%d为例,scanf()会先忽略stdin中的空白符,直到遇到第一个0-9开始读取,如果后面的字符依然是0-9就继续读取,直到遇到空白符或者非0-9的字符,scanf认为%d的读取完毕,将读取的字符序列转换成十进制整型保存到变量中。最后遇到的空白符或非法字符将返回到stdin中去。
如果忽略掉前面的空白符后第一个遇到的是非法的字符(非0-9),比如a,这时a会被返回到stdin中,程序也将会跳出scanf()函数(不管%d后面是否还存在带输入项,如另一个%d,都会跳出整个scanf()函数)。
看一个例子:
#include <stdio.h> #include <stdlib.h> int main() { int a=123; int b=11; char c[10]; printf("请输入:\\n"); scanf("%d%d",&a,&b); scanf("%s",c); printf("a=%d,b=%d,c=%s\\n",a,b,c); return 0; }
输入和输出结果为:
可以看到我在相邻的两个待输入字段之间添加了多个空白符,但是这并不会影响输入(当有%c的时候会有影响),这就是因为scanf()在读取每个待输入字段前都会跳过前面的空白符。
同样的程序,在看一组输入和输出结果。
这个我先输入了一个对于%d是非法的字符s,第一个scanf()读取的时候会先跳过s前面的空白符,然后遇到s,发现s与%d不能匹配,这时候就会将s返回到stdin中,并跳过第一个scanf(),所以我们看到a和b的值都没有被改变,然后开始执行第二个scanf(),这个时候遇到的第一个字符是s(之前scanf返回到stdin中),然后接着读取,1、2、3、4知道遇到空白符,认为%s读取结束,将读入的字符序列转换称一个字符串(添加上\'\\0\'),然后保存到c所指的地址中。
再来看一个格式字符串中含有普通字符的例子。
#include <stdio.h> #include <stdlib.h> int main() { int a=123; int b=11; char c[10]; printf("请输入:\\n"); scanf("%d,%d",&a,&b); scanf("%s",c); printf("a=%d,b=%d,c=%s\\n",a,b,c); return 0; }
与上一个例子不同的是第一个scanf()的两个%d之间多个一个",",这时在输入的时候要特别注意也要输入这个逗号,而且这个逗号相对于前一个%d的位置也要准确,否则scanf()就会读取失败,然后跳出这个scanf().
看一个正确的输入:
如果我们输入的时候95后面跟的不是逗号(全半角错误也不行),scanf就会读取失败,然后将该字符返回到stdin中,然后跳过这个scanf。
看一个错误的输入
这次输入时95后面的是中文形式的逗号,与代码中英文形式的逗号不匹配,这个时候就会出错,然后中文的逗号就会被返回到stdin中,并跳出第一个scanf,开始第二个scanf(),所以b的值没有读取进去。而c的值中也含有第一个scanf()返回到stdin中的逗号。
再看一中错误的输入:
这次在95后面添加了几个空白符,然后才是逗号。前面强调scanf在读取每个待输入的字段的时候都会跳过空白符,但是要明白,对于第一个scanf(),它的待输入项就是两个%d,逗号并不是它的待输入项,所以逗号前面的空白符不会被跳过,所以出现了和代码中的逗号不匹配的情况(实际的输入是空格),所以也会像前一种情况一样读取错误,并跳过第一个scanf。
再看一种正确的输入:
这个输入中我们在逗号后面添加了多个空格,发现输入时正确的。这是因为这些空格位于第二个%d的前面,也就是说位于第二个待输入项的前面,这时scanf就会跳过这些空白符。
再看一种代码:
#include <stdio.h> #include <stdlib.h> int main() { int a=123; int b=11; char c[10]; printf("请输入:\\n"); scanf("%d\\n,%d",&a,&b); scanf("%s",c); printf("a=%d,b=%d,c=%s\\n",a,b,c); return 0; }
这次我们在第一个%d和逗号之间添加了一个\\n(其实只要是空白符即可)。
输入输出结果
这次我们发现在95和逗号之间添加了多个空白符也正确,这是因为添加的\\n会让scanf()跳过%d和逗号之间的空白符。将\\n换成空格也是正确的(只要是空白符就行)
比如换成空格:
#include <stdio.h> #include <stdlib.h> int main() { int a=123; int b=11; char c[10]; printf("请输入:\\n"); scanf("%d ,%d",&a,&b); scanf("%s",c); printf("a=%d,b=%d,c=%s\\n",a,b,c); return 0; }
最后看一种含有%c的情况
#include <stdio.h> #include <stdlib.h> int main() { int a=123; int b=11; char c; printf("请输入:\\n"); scanf("%d,%d",&a,&b); scanf("%c",&c); printf("a=%d,b=%d,c=%c\\n",a,b,c); return 0; }
我们输入95,21回车,scanf的读取流程是这样的:
首先遇到95然后遇到逗号,发现逗号和%d不匹配,就将95转换成整型保存到a中,并将逗号返回到stdin中,然后继续读取,读取到逗号(刚刚返回到stdin中的)发现和代码中的逗号匹配,所以会跳过这个逗号,然后读取到21,然后是回车,发现空白符,则认为第二个%d读取结束,所以讲21转换成整型保存到b中,并返回空白符回车到stdin中,接着开始进行第二个scanf函数,其中%c可以读取任何字符(通吃啦),所以空白符对于%c来说是合法的,回车自然也是合法的,所以它就将回车保存到了c中。所以我们看到输出结果中c的内容为空,但是Press any key to continue前面有一行空行,这实际上就是读入到c中的换行符。
所以如果我们输入的是95,21空格(多个)x回车,那么空格就将被读入到c中,除了第一个空格,其余的字符还在stdin中:
那么怎么解决这种问题呢? 因为毕竟我们想让c读取x,而并不是空格。
一种可能的解决方法是在第一个scanf()的最后一个%d后面加入一个空白符(空格、\\n、\\t都是可以的),以吸收21和x之间的空白符。(我才用的是\\n)
#include <stdio.h> #include <stdlib.h> int main() { int a=123; int b=11; char c; printf("请输入:\\n"); scanf("%d,%d\\n",&a,&b); scanf("%c",&c); printf("a=%d,b=%d,c=%c\\n",a,b,c); return 0; }
结果是正确 ^^
先写到这里啦,有问题再补充。。
如果你觉得对你有一丝的帮助,请点赞哦 ^^
补充:当scanf中使用数字修饰限制字段的长度时,遇到空白符(或非法字符)或者达到字段长度(二者满足一个即可)就意味着这个字段读取完成了
再补充一点,关于scanf的返回值,scanf返回正确读入数据的个数。0表示一个都没有正确输入,EOF表示读到了EOF,在linux中Ctrl+D表示EOF
如果你觉得对你有一丝的帮助,请点赞哦 ^^
以上是关于用scanf同时输入不同类型的成员数据常常会出现意想不到的情况,这是为啥呢?的主要内容,如果未能解决你的问题,请参考以下文章