scanf的用法大全

索引:

1、scanf函数的一般形式
2、附加格式说明字符表修饰符说明 
3、问题一:scanf()函数不能正确接受有空格的字符串?
4、scanf()函数如何结束数据的输入
5、问题二:键盘缓冲区残余信息问题
6、问题三: 如何处理scanf()函数误输入造成程序死锁或出错?
7、%[ ] 的用法

===========================================================================

http://hdongq.blog.163.com/blog/static/169402621201021011158231/

scanf函数的一般形式  scanf(格式控制,地址表列)
  int scanf(char *format[,argument,...]);
  
“格式控制”的含义同printf函数;“地址表列”是由若干个地址组成的表列,可以是变量的地址,或字符串首地址。
  scanf()函数返回成功赋值的数据项数,读到文件末尾出错时则返回EOF。
  例:使用scanf函数输入数据。
  #include
  void main()
  {
  int a,b,c;
  printf("input a,b,c\n");
  scanf("%d%d%d",&a,&b,&c);
  printf("a=%d,b=%d,c=%d",a,b,c);
  }

格式字符说明  %a,%A 读入一个浮点值(仅C99有效) 
  %c 读入一个字符
  %d 读入十进制整数
  %i 读入十进制,八进制,十六进制整数
  %o 读入八进制整数
  %x,%X 读入十六进制整数
  %c 读入一个字符
  %s 读入一个字符串,遇空格、制表符或换行符结束。
  %f,%F,%e,%E,%g,%G 用来输入实数,可以用小数形式或指数形式输入。
  %p 读入一个指针
  %u 读入一个无符号十进制整数
  %n 至此已读入值的等价字符数
  %[] 扫描字符集合
  %% 读%符号
  
  附加格式说明字符表修饰符说明
 
  L/l 长度修饰符 输入"长"数据
  h 长度修饰符 输入"短"数据
  W 整型常数 指定输入数据所占宽度
  * 表示本输入项在读入后不赋值给相应的变量

 scanf的返回值  scanf的返回值有后面的参数决定

   scanf("%d%d", &a, &b);
  
如果a和b都被成功读入,那么scanf的返回值就是2
  如果只有a被成功读入,返回值为1
  如果a和b都未被成功读入,返回值为0
  如果遇到错误或遇到end of file,返回值为EOF。
  且返回值为int型

 

使用scanf函数时应该注意的问题 

 1、sacnf()中的变量必须使用地址。 
  2、scanf()的格式控制串可以使用其它非空白字符,但在输入时必须输入这些字符。
  3、在用"%c"输入时,空格和“转义字符”均作为有效字符。
  问题一:scanf()函数不能正确接受有空格的字符串?如: I love you!
  #include 
  int main()
  {
  char str[80];
  scanf("%s",str);
  printf("%s",str); 
  return 0;
  }
  输入:I love you!
  输出:

scanf()函数接收输入数据时,遇以下情况结束一个数据的输入:(不是结束该scanf函数,scanf函数仅在每一个数据域均有数据,并按回车后结束)。
  ① 遇空格、“回车”、“跳格”键。
  ② 遇宽度结束。
  ③ 遇非法输入。

  
所以,上述程序并不能达到预期目的,scanf()扫描到"I"后面的空格就认为对str的赋值结束,并忽略后面的"love you!".这里要注意是"loveyou!"还在键盘缓冲区(关于这个问题,网上我所见的说法都是如此,但是,我经过调试发现,其实这时缓冲区字符串首尾指针已经相等了,也就是说缓冲区清空了,scanf()函数应该只是扫描stdin流,这个残存信息是在stdin中)。我们改动一下上面的程序来验证一下:
  #include 
  #include
  int main()
  {
  char str[80];
  char str1[80];
  char str2[80];
  scanf("%s",str);/*此处输入:I love you! */
  printf("%s",str);
  Sleep(5000);/*这里等待5秒,告诉你程序运行到什么地方*/     /*不是sleep(5) 1,函数名是Sleep不是sleep。2,C/C++中,unsigned Sleep(unsigned)应该是毫秒ms.
  scanf("%s",str1);/*这两句无需你再输入,是对键盘盘缓冲区再扫描 */
  scanf("%s",str2);/*这两句无需你再输入,是对键盘盘缓冲区再扫描 */
  printf("\n%s",str1);
  printf("\n%s",str2);
  return 0;
  }
  输入:I love you!
  输出:
  I
  love
  you!
  好了,原因知道了,那么scanf()函数能不能完成这个任务?回答是:能!别忘了scanf()函数还有一个 %[] 格式控制符(如果对%[]不了解的请查看本文的上篇),请看下面的程序:
  #include "stdio.h"
  int main()
  {
  char string[50];/*scanf("%s",string);不能接收空格符*/
  scanf("%[^\n]",string);
  printf("%s\n",string);
  return 0;
  }
  问题二:键盘缓冲区残余信息问题
  #include 
  int main()
  {
  int a;
  char c; do
  {
  scanf("%d",&a);
  scanf("%c",&c);
  printf("a=%d c=%c\n",a,c);/*printf("c=%d\n",c);*/
  }while(c!='N');
  } 
  scanf("%c",&c);这句不能正常接收字符,什么原因呢?我们用printf("c=%d\n",c);将C用int表示出来,启用printf("c=%d\n",c);这一句,看看scanf()函数赋给C到底是什么,结果是c=10,ASCII值为10是什么?换行即\n.对了,我们每击打一下"Enter"键,向键盘缓冲区发去一个“回车”(\r),一个“换行"(\n),在这里\r被scanf()函数处理掉了(姑且这么认为吧^_^),而\n被scanf()函数“错误”地赋给了c.解决办法:可以在两个scanf()函数之后加个fflush(stdin);,还有加getch() , getchar()也可以,但是要视具体scanf()语句加那个,这里就不分析了,读者自己去摸索吧。但是加fflush(stdin);不管什么情况都可行。
  

  函数名: fflush 
  功 能: 清除一个流
  用 法: int fflush(FILE *stream);
  )
  #include 
  int main()
  {
  int a;
  char c; do
  {
  scanf("%d",&a);
  fflush(stdin);
  scanf("%c",&c);
  fflush(stdin);
  printf("a=%d c=%c\n",a,c); }while(c!='N');
  } 
  这里再给一个用“空格符”来处理缓冲区残余信息的示例:运行出错的程序:
  #include 
  int main()
  {
  int i;
  char j;
  for(i = 0;i < 10;i++)
  {
  scanf("%c",&j);/*这里%前没有空格*/
  }
  }
  使用了空格控制符后:
  #include 
  int main()
  {
  int i;
  char j;
  for(i = 0;i < 10;i++)
  {
  scanf(" %c",&j);/*注意这里%前有个空格*/
  }
  } 
  可以运行看看两个程序有什么不同。
  问题三: 如何处理scanf()函数误输入造成程序死锁或出错?
  #include 
  int main()
  {
  int a,b,c; /*计算a+b*/
  scanf("%d,%d",&a,&b);
  c=a+b;
  printf("%d+%d=%d",a,b,c);
  }
  如上程序,如果正确输入a,b的值,那么没什么问题,但是,你不能保证使用者每一次都能正确输入,一旦输入了错误的类型,你的程序不是死锁,就是得到一个错误的结果,呵呵,这可能所有人都遇到过的问题吧?解决方法:scanf()函数执行成功时的返回值是成功读取的变量数,也就是说,你这个scanf()函数有几个变量,如果scanf()函数全部正常读取,它就返回几。但这里还要注意另一个问题,如果输入了非法数据,键盘缓冲区就可能还个有残余信息问题。正确的例程:
  #include 
  int main()
  {
  int a,b,c; /*计算a+b*/
  while(scanf("%d,%d",&a,&b)!=2)fflush(stdin);
  c=a+b;
  printf("%d+%d=%d",a,b,c);
  }
  补充: fflush(stdin)这个方法在GCC下不可用。(在VC6.0下可以)
  以下是 C99 对 fflush 函数的定义:
  int fflush(FILE *stream);
  如果stream指向输出流或者更新流(update stream),并且这个更新流
  最近执行的操作不是输入,那么fflush函数将把任何未被写入的数据写入stream
  指向的文件(如标准输出文件stdout)。否则,fflush函数的行为是不确定的。
  fflush(NULL)清空所有输出流和上面提到的更新流。如果发生写错误,fflush
  函数会给那些流打上错误标记,并且返回EOF,否则返回0。
  由此可知,如果 stream 指向输入流(如 stdin),那么 fflush 函数的行为是不确定的。故而使用
  fflush(stdin) 是不正确的,至少是移植性不好的。

  可采用如下方法:
  /* 此函数可以和scanf函数一起使用,但使用%c输入时要注意,即此函数只能用于缓冲区非空的情况 */
  void flush() 
  {
  char c;
  while ((c=getchar()) != '\n'&&c!=EOF) ;
  }
  #include 
  int main()
  {
  int a,b,c; /*计算a+b*/
  while(scanf("%d,%d",&a,&b)!=2) flush();
  c=a+b;
  printf("%d+%d=%d",a,b,c);
  }

http://blog.csdn.net/lbird/archive/2007/08/03/1724429.aspx

sscanf/scanf特殊用法  
%[ ]
的用法:%[ ]表示要读入一个字符集合, 如果[ 后面第一个字符是”^”,则表示反意思。

                    [ ]内的字符串可以是1或更多字符组成。空字符集(%[])是违反规定的,可

                    导致不可预知的结果。%[^]也是违反规定的。
         

%[a-z] 读取在 a-z 之间的字符串,如果不在此之前则停止,如

             char s[]="hello, my friend” ;         // 注意: ,逗号在不 a-z之间

             sscanf( s, “%[a-z]”, string ) ; // string=hello


%[^a-z]
读取不在 a-z 之间的字符串,如果碰到a-z之间的字符则停止,如

             char s[]="HELLOkitty” ;         // 注意: ,逗号在不 a-z之间

             sscanf( s, “%[^a-z]”, string ) ; // string=HELLO


%*[^=]   
前面带 * 号表示不保存变量。跳过符合条件的字符串。

             char s[]="notepad=1.0.0.1001" ;

       char szfilename [32] = "" ;

       int i = sscanf( s,"%*[^=]", szfilename ) ; // szfilename=NULL,因为没保存

int i = sscanf( s, "%*[^=]=%s", szfilename ) ; //szfilename=1.0.0.1001

%40c      读取40个字符

             The run-time

library does not automatically append a null terminator

to the string, nor does reading 40 characters

automatically terminate the scanf() function. Because the

library uses buffered input, you must press the ENTER key

to terminate the string scan. If you press the ENTER before

        the scanf() reads 40characters, it is displayed normally,

        and the library continues toprompt for additional input

        until it reads 40 characters


%[^=]    
读取字符串直到碰到’=’号,’^’后面可以带更多字符,如:

             char s[]="notepad=1.0.0.1001" ;

       char szfilename [32] = "" ;

       int i = sscanf( s, "%[^=]",szfilename ) ; // szfilename=notepad     

       如果参数格式是:%[^=:] ,那么也可以从 notepad:1.0.0.1001读取notepad

             

使用例子:

       chars[]="notepad=1.0.0.1001" ;

char szname [32] = "" ;

char szver [32] = “” ;

sscanf( s, "%[^=]=%s", szname , szver ) ; // szname=notepad, szver=1.0.0.1001

总结:%[]有很大的功能,但是并不是很常用到,主要因为:

1、许多系统的 scanf 函数都有漏洞. (典型的就是 TC 在输入浮点型时有时会出错).

2、用法复杂, 容易出错.

3、编译器作语法分析时会很困难, 从而影响目标代码的质量和执行效率.

个人觉得第3点最致命,越复杂的功能往往执行效率越低下。而一些简单的字符串分析我们可以自已处理。

 

你可能感兴趣的:(C基础学习)