scanf()函数探讨——常见错误和解答

1.空白符问题

#include<stdio.h>
main()
{  
   int a;
   printf("input the data/n");
   scanf("%d/n",&a);//
这里多了一个回车符/n
   printf("%d",a);
   return 0;
}

结果要输入两个数程序才结束,而不是预期的一个。
原因:用空白符结尾时,scanf会跳过空白符去读下一个字符,所以你必须再输入一个数。这里的空白符包括空格,制表符,换行符,回车符和换页符。所以如果你用scanf("%d ",&a)也会出现同样的问题。
解决方法:这种错误大多是输入的时候不小心,多注意一点就好了。这种问题也不好检查,编译没有问题,一个空格也不容易看出来。当你的程序出现上面的问题时,自己对照检查一下就可以了。

2.缓冲区问题
这是一个非常容易错的地方。

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


如果输入:
a
b
c
那么循环就会“提前”结束了
.
原因:输入a和第一个回车后,a和这个回车符都留在缓冲区中。第一个scanf读取了a,但是输入缓冲区里面还留有一个/n,第二个scanf读取这个/n。然后输入b和第二个回车,同样的,第三个scanf读取了b,第四个scanf读取了第二个回车符。第五个读取了c。所以五个scanf都执行了,并没有提前结束。只不过有的scanf读取到了回车符而已。

解决方法:把程序改成这样就可以了:

for( i = 0; i < n; i++){
   scanf("%c",&c[i]);
fflush(stdin);//
刷新缓冲区
}

或者不用scanf,而用gets()函数,如:

#include<stdio.h>
main()
{  
   char c[5];
   gets(c);
   printf(c);
   return 0;
}

但要注意:这个函数自动把你最后敲的回车转换为字符'/0'。如果你的输入超过了数组的大小,那么就会产生错误。


3.scanf()
函数的参数输入类型不匹配问题
这是我在csdn论坛上见到的问题,这个错误有时候会让人莫名其妙。

#include<stdio.h>
main()
{
int a=123;
char c='t';
printf("input/n");
scanf("%d%c",&a,&c);
scanf("%d%c",&a,&c);
scanf("%d%c",&a,&c);
printf("%d/n%c/n",a,c);
return 0;
}

当输入a 回车 后,会直接跳过下面2个scanf语句,直接输出为
123
t
原因:对于scanf("%d%c",&a,&c),scanf语句执行时,首先试图从缓冲区中读入一个%d类型的数据,如果和第一个参数匹配,则继续从缓冲区中读取数据和第二个参数进行匹配,依次进行下去,直到匹配完所有的参数;如果其中有一个参数不匹配,那就从这个地方跳出,忽略这个 scanf后面所有的参数,而去执行下一条语句。
可以用下面的程序验证一下:

#include <stdio.h>
int main()
{
int a=123,b=1;
char c='t';
   scanf("%d%d",&a,&b);
scanf("%c",&c);
printf("%d/n%d/n%c/n",a,b,c);
return 0;
}

输入:2 回车a 回车
结果是:
2
1
a
解决方法:scanf()函数执行成功时的返回值是成功读取的变量数,也就是说,你这个scanf()函数有几个变量,如果scanf()函数全部正常读取,它就返回几。但这里还要注意另一个问题,如果输入了非法数据,键盘缓冲区就可能还个有残余信息问题。
比如:

#include <stdio.h>
main()
{
int a=123,b;
while(scanf("%d%d",&a,&b)!=2)
   fflush(stdin);
printf("%d/n%d/n",a,b);
return 0;
}

你可以试一下,如果输入不是数字时,会有什么反应。

补充:scanf中一种很少见但很有用的转换字符:[...]和[ ^...]。

#include<stdio.h>
main()
{
char strings[100];
scanf("%[1234567890]",strings);
printf("%s",strings);
return 0;
}

运行,输入:1234werew后,结果是:1234。通过运行可以发现它的作用是:如果输入的字符属于方括号内字符串中某个字符,那么就提取该字符;如果一经发现不属于就结束提取。该方法会自动加上一个字符串结束符到已经提取的字符后面。
    scanf("%[^1234567890]",strings); 它的作用是:如果一经发现输入的字符属于方括号内字符串中某个字符,那么就结束提取;如果不属于就提取该字符。该方法会自动加上一个字符串结束符到已经提取的字符后面。

    注意:方括号两边不能空格,如:scanf("%[ 1234567890 ]",strings); scanf("%[ ^1234567890 ]",strings); 不让空格也会算在里面的。用这种方法还可以解决scanf的输入中不能有空格的问题。只要用scanf("%[^/n]",strings); 就可以了。很神奇吧。

4.一些问题
问题1

#include<stdio.h>

void   main()

{

       static int a[2][3]={{1,3,4},{7,9,6}};

       int i,j,k;

       for(k=1;k<=2;k++)

       {printf("Please input num:");

       scanf("%d %d",&i,&j);

       if(i<2&&j<3)

               printf("num=%d/n",a[i][j]);

       else printf("Input is error,/n");

       }

       printf("programm is complete./n");

}

如果将第8行改为

scanf("i=%d j=%d",&i,&j);

则程序运行结果变成

please input num:i=1 j=2

num=6

Programm is complete. (原本希望能重复第一行再让我输入)

为什么第二次不能输入?

解答:象scanf("i=%d j=%d",&i,&j);这样的输入方式比较特别,显然在第一次输入后没有象正常情况一样清楚输入缓冲区,这样第二次执行scanf时,程序并没有让你输入而是直接读入上次输入的结果。如果你一定要 这么做,应该在scanf之前加上: fflush(stdin);

这样清楚掉键盘缓冲区。



问题2

为什么要把scanf("%c",varname)一定改成scanf(" %c")才可以正确接收字符?

答复:

类似上题,在%c的前面必须有一个空格,否则系统会将你前面输入别的值之后键入的回车符读入该变量,造成死循环。当然,如果scanf("%c",&varname)是第一条读入语句,就可以不需要空格。


问题3:(输入字符的格式与要求不一致)

在用“%c”格式输入字符时,“空格字符”和“转义字符”都作为有效字符输入。

scanf("%c%c%c",&c1,&c2,&c3);

如输入a b c

字符“a”送给c1,字符“ ”送给c2,字符“b”送给c3,因为%c只要求读入一个字符,后面不需要用空格作为两个字符的间隔。


问题4:(输入输出的数据类型与所用格式说明符不一致)

例如,a已定义为整型,b定义为实型

a=3;b=4.5;

printf("%f%d/n",a,b);

编译时不给出出错信息,但运行结果将与原意不符。这种错误尤其需要注意。


问题5:(输入数据时,企图规定精度)

scanf("%7.2f",&a);

这样做是不合法的,输入数据时不能规定精度。


问题6:(在不应加地址运算符&的位置加了地址运算符)

scanf("%s",&str);

C语言编译系统对数组名的处理是:数组名代表该数组的起始地址,且scanf函数中的输入项是字符数组名,不必要再加地址符&。应改为:scanf("%s",str);

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值