免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3162 | 回复: 5

使用scanf()总结 [复制链接]

论坛徽章:
0
发表于 2007-03-12 17:06 |显示全部楼层
下午闲来无事,在win和linux上编程玩,结果碰到了使用scanf()这个函数一点麻烦。在高手指引下终于知道了问题的所在。呵呵,还得再说声谢谢。
    趁着这个机会整理了点网上比较多的有关scanf()的用法,和朋友们分享一下:
=========================================================
scanf()函数执行成功时的返回值是成功读取的变量数,也就是说,你这个scanf()函数有几个变量,如果scanf()函数全部正常读取

,它就返回几。但这里还要注意另一个问题,如果输入了非法数据,键盘缓冲区就可能还个有残余信息问题。
=============================================================
End.

论坛徽章:
0
发表于 2007-03-12 17:09 |显示全部楼层
不好意思,有点晕了。
使用scanf()常犯错误:(网络帖子总结)
------------------------------------------------------------------------  
<1>        本意:接收字符串.
       写成代码:void main()
                 {
                 char *str;
                 scanf("%s",str);
                 printf("string is: %s\n",str);
                 }
   符合愿意代码:char *str=NULL;
                 str=malloc(128*sizeof(char) );
                 scanf( "%s\n", str );
           点评:指针需要你手动给它分配空间,并手动指向该空间如果没有,指针指向哪里,是不确定的
                 也就是说,你scanf得到的数据存放到哪里是不一定的因此,偶尔有运行正常是你运气好
                 错误才是正常的
-----------------------------------------------------------------------
<2>        本意:接收输入的a,b值.
       写成代码:int a,b;
                 scanf("%d%d",a,b);
   符合愿意代码:int a,b;
                 scanf("%d%d",&a,&b);
           点评:这是不合法的。Scanf函数的作用是:按照a、b在内存的地址将
                 a、b的值存进去。“&a”指a在内存中的地址。
------------------------------------------------------------------------
<3>        本意:在Input字符串后输入数值.
       写成代码:int num;
                 Scanf("Input %d", & num);
     实际应输入:Input 1234 或者 Input1234
   符合愿意代码:int num;
                 printf("Input";
                 scanf("%d",&num);
------------------------------------------------------------------------  
<4>        本意:接收填入的数据.
       写成代码:#include <stdio.h>
                 main()
                {
                 int num;
                 printf("please input the student's score: ";
                 scanf("%d",&num);

                 if((num<0)||(num>100))
                 {
                      printf("The score put isnt fine. please run and input again.";
                 }
                 else if(num>90)
                 {
                      printf("The grade is A.";
                 }
               
                 else if((num>80)&&(num<90))
                 {
                     printf(..................
                     .............
                 }
                 ..............
                        
                 }
     实际应输入:这个程序是没错,不过如果有人要存心捣乱, 输入时不是输入数字,而是其
                 他的什么字符,那么congratulations,这个程序崩溃掉了.
   符合愿意代码:#include <stdio.h>
                 main()
                {
                 int num,int result=0;
                 printf("please input the student's score: ";
                  
                 while(result==0)
                {
                 fflush(stdin);  /*  清空输入缓冲区. */
                 if(result!=1)printf("lease input a digital score: ";
                 result=scanf("%d",&num);  
                }
                ............................
                }
           点评:scanf函数执行成功时的返回值为成功读取的变量数,如果第一个变量的读取既告失败则返回值为0.   
                 我们可以通过判断scanf函数执行的返回值,  可以制止用户不正确地输入,从而控制程序的流程.
           另 :#include <stdio.h>
                 int main()
                {
                       char b[2];
                       scanf("%s", b);
                       printf("%s\n", b);
                }
                如果输入的字符比较多例如10个,就会seg fault,可见scanf是不安全的,没有检查缓冲区。
                同样,把上面的scanf换成gets,效果是一样的。(而且编译的时候有warning,不让用gets)。
                fgets是安全的,这样用法:
                fgets(b, 2, stdin);
                注意,这样子其实只读了一个字符,第二个字符是0。所以如果输入是sad,则b[0]='s', b[1]=0.
                由此可见,读入字符串时,fgets更安全。
------------------------------------------------------------------------                     
<5>        本意:接收带空格等的字符串.
       写成代码:#include <stdio.h>
                 void main(){
                 char c[100];
                 scanf("%s", c);
                 printf("%s", c);
                 }
           输入:welcome to come here
           输出:welcome
   符合愿意代码:换用gets();
           点评:因为输入终端的buffer把空白字符(包括空格。\t等)当成字符串分隔符,
                 你用过命令行参数就明白了,main函数的参数是 int main(int,char*[])
------------------------------------------------------------------------  
<6>        本意:接收规定精度的数据.
       写成代码:scanf("%7.2f",&a);
     实际应输入:
   符合愿意代码:
           点评:这样做是不合法的,输入数据时不能规定精度。
------------------------------------------------------------------------  
<7>        本意:正确输入a,b的值.
       写成代码:#include <stdio.h>
                 int main()
                 {
                  int a,b,c;  /*计算a+b*/
                  scanf("%d,%d",&a,&b);
                  c=a+b;
                  printf("%d+%d=%d",a,b,c);
                 }
           现象:一旦输入了错误的类型,程序不是死锁,就是得到一个错误的结果。
   符合愿意代码:#include <stdio.h>
                 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);
                }
           点评:scanf()函数执行成功时的返回值是成功读取的变量数,也就是说,
                 你这个scanf()函数有几个变量,如果scanf()函数全部正常读取,
                 它就返回几。但这里还要注意另一个问题,如果输入了非法数据,
                 键盘缓冲区就可能还个有残余信息问题。
------------------------------------------------------------------------  
<8>        本意:可以连续多次接受数据.
       写成代码:#include <stdio.h>
                 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);这句不能正常接收字符
   符合愿意代码:#include <stdio.h>
                 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');
                 }      
           点评:我们用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.
             另:fflush(FILE *stream)函数,其主要功能:可将所有缓冲区数据写入指定的流文件将
                 清空缓冲区。
------------------------------------------------------------------------  
<9>        本意:接收float型数值.
       写成代码:#include "stdio.h"
                main()
                {
                 int i=0;
                 struct BOOK
                  {
                     char bookName[100];
                     float bookPrice;
                  };
                  struct BOOK book[10];
                  for(i=0;i<10;i++)
                  {
                      scanf("%f",&book[i].bookPrice);
                  }
                }
           现象:  编译通过,但运行时报错(TC3.0):
                   scanf : floating point formats not linked.
                   Abnormal program termination 。
   符合愿意代码:#include "stdio.h"
                main()
                {
                  int i=0;
                 float t=0;
                 struct BOOK
                 {
                    char bookName[100];
                    float bookPrice;
                  };
                  struct BOOK book[10];
                  for(i=0;i<10;i++)
                  {
                      scanf("%f",&t);
                      book[i].bookPrice=t;
                  }
                }
   相关参考资料:
Description:
  This document explains why you might be getting the error
  FLOATING POINT FORMATS NOT LINKED : ABNORMAL PROGRAM TERMINATION
  and tells you how to resolve it.  The problems and solutions
  below apply to ALL versions of Turbo C, Turbo C++, and Borland
  C++, except where noted.
  What are floating point formats?
  Floating point formats are a collection of formatting information
  used to manipulate floating point numbers in certain runtime
  library functions such as scanf() and atof().
  When will this be fixed?
  There are no current plans to fix this because it is not a bug.
  The intent is to avoid linking the floating point formats (about
  1K of overhead) when they are not required.  The tradeoff of this
  feature is that the programmer must explicitly request that the
  floating point formats to be linked in for some programs which
  manipulate floats in a limited and specific fashion.
  How do I resolve the error message?
  Since you can get the error in a number of different ways, check
  the following list of potential causes to find out how to resolve
  the error.  These are listed in order of most common to least
  common causes.
  1.  CAUSE:  Floating point set to .  Your have your
      floating point option set to None when it should be set to
      either Emulation or 80x87.
      FIX:  Set Floating Point to  or <80x87>.  In the
      Integrated Development Environment (IDE), this is either
      under Options | Compiler | Advanced Code Generation or
      Options | Compiler | Code Generation | More, depending upon
      which compiler you have.  With the command line compiler, use
      the appropriate -f switch.
  2.  CAUSE:  Misordered libraries when executing TLINK
      (Cx.LIB listed before EMU.LIB will cause the error.)
      FIX:  This possibility usually occurs only when you are using
      the command line compiler and are explicitly calling TLINK
      separately from BCC or TCC.  When executing TLINK, change the
      order of the libraries to
           [user libs] [GRAPHICS.LIB] EMU.LIB MATHx.LIB Cx.LIB
                  (libraries in brackets are optional)
      Note:  There is a misprint in the Borland C++ Tools &
      Utilities Guide on page 58 that displays the wrong order for
      libraries on the TLINK command line.  The ordering shown in
      the manual is exactly what will cause floating point formats
      not linked.
  3.  CAUSE:  Either the compiler is overoptimizing, or the
      floating point formats really do need to be linked in because
      your program manipulates floats in a limited and specific
      fashion.  Under certain obscure conditions, the compiler will
      ignore floating point usage in scanf().  (e.g., trying to
      read into a float variable that is part of an array contained
      in a structure.)
      FIX:  If you have Borland C++ 3.0 or later, read Part A.  If
      you have Borland C++ 2.0 or any Turbo C or Turbo C++
      compiler, read Part B.  This fix is the only fix that will
      solve a "RINTF : Floating point formats not linked" error
      message occurring with inline assembly.
      Part A (BC++ 3.0 or later):
          Add the following to one source module:
              extern _floatconvert;
              #pragma extref _floatconvert
          The README and HELPME!.DOC files that shipped with
          Borland C++ 3.0 incorrectly say that only
              #pragma extref _floatconvert
          is required in order to resolve the FPFNL error.  If you
          do not include the "extern _floatconvert;" line you will
          get the error "Undefined symbol _floatconvert."  You will
          also get the same undefined symbol if the "extern
          _floatconvert" comes after the #pragma line instead of
          before.  Note that the #pragma line does not have a
          semicolon at the end of the line.  If you put a semicolon
          there, you will get the error "Bad pragma directive
          syntax."
          The README that shipped with Borland C++ 3.1 says that
              extern void _floatconvert();
              #pragma extref _floatconvert
          This should work, as well.  It doesn't really matter
          whether _floatconvert is a variable or a function; it
          only matters that it is some symbol that the linker will
          recognize.
          The HELPME!.DOC for BC++ 3.1 has the correct two lines to
          add.
      Part B (BC++ 2.0 or TC or TC++):
          Add the following force_fpf() function to one source
          module.  It is not necessary to call this function; just
          include it in one of your modules.
          static void force_fpf()
          {
              float x, *y; /* Just declares two variables */
              y = &x;      /* Forces linkage of FP formats */
              x = *y;      /* Suppress warning message about x */
          }
  4.  CAUSE:  Forgetting to put the address operator & on the scanf
      variable expression.  For example,
          float foo;
          scanf("%f", foo);
      FIX:  Change the code so that the & operator is used where it
      is needed.  For example, the above code should be
          float foo;
          scanf("%f", &foo);
  5.  CAUSE:  A bug in Turbo C 2.0 when using scanf()
      FIX:  Obtain and apply the patches in TC2PAT.ARC.  This file
      can be downloaded from the Languages / C++ / Patches section
      on DLBBS (408-439-9096).
  6.  CAUSE:  A bug in Turbo C 2.01 when using atof() or strtod()
      FIX:  Obtain and apply the patches in TC21PT.ARC.  This file
      can be downloaded from the Languages / C++ / Patches section
      on DLBBS (408-439-9096).
  7.  CAUSE:  You are trying to create a Phar Lap DOS Extender
      application with the Integrated Development Environment
      (IDE).
      FIX:  Phar Lap includes an executable called BCC286.EXE with
      their DOS Extender.  This program calls Borland's command-
      line compiler (BCC) and command-line linker (TLINK).  Since
      the linker in the IDE is different than the linker at the
      command line, you cannot create Phar Lap DOS Extender
      applications in the IDE and expect them to run properly.  If
      you try to do so, you might get a floating point formats not
      linked error message.  The fix is to use the command line
      tools, BCC and TLINK, instead of the IDE.
  Keywords:  FPFNL , APT
  DISCLAIMER: You have the right to use this technical information
  subject to the terms of the No-Nonsense License Statement that
  you received with the Borland product to which this information
  pertains.
------------------------------------------------------------------------  
其他:   
   在scanf函数中,我们可以使用 %c来读取一个字符,使用 %s 读取一个字符串. 但是读取字
符串时不忽略空格,读字符串时忽略开始的空格,并且读到空格为止,因此我们只能读取一个单
词,而不是整行字符串.因此一般使用fgets来读取一个字符串.其实scanf函数也可完成这样的
功能,而且还更强大.
   这里主要介绍一个参数,%[ ] ,这个参数的意义是读入一个字符集合. [ ]是个集合的标
志,因此%[ ]特指读入此集合所限定的那些字符, 比如 %[A-Z] 是输入大写字母,一旦遇到不在
此集合的字符便停止. 如果集合的第一个字符是" ^ ", 这说明读取不在" ^ " 后面集合的字
符,既遇到" ^ " 后面集合的字符便停止.注意此时读入的字符串是可以含有空格的.
  Eg.  输入一个字符串, 这个字符串只含有小写字符.遇到第一个不是小写字符时停止.
      scanf("%[a-z],str);
  Eg.  想输入一个字符串, 遇到 "." 停止,可设计如下:
     scanf("%[^.]", str);
    使用这个参数,你可以完成许多强大的功能呦!
------------------------------------------------------------------------------------------------------------------------
总结:  通常来讲,scanf函数和他的一些参数并不是很常用,主要是因为:
       1.许多系统的scanf函数都有漏洞. (典型的就是TC再输入浮点型时有时会出错).
       2.用法复杂,容易出错.
       3.编译器作语法分析时会很困难,从而影响目标代码的质量和执行效率.

论坛徽章:
0
发表于 2007-03-12 17:10 |显示全部楼层
怎么机子上.txt的格式是好的,复制过来就乱七八糟了?看来本人还得学习怎么发贴

论坛徽章:
0
发表于 2007-03-12 17:16 |显示全部楼层
请使用
[ c o d e ]   [ / c o d e ]


包裹你的代码

(去掉[]中间的空格)

论坛徽章:
0
发表于 2007-03-12 20:37 |显示全部楼层
不错,给初学者看不错,一些比较全面的C语言书上应该有介绍吧~

论坛徽章:
0
发表于 2007-03-13 14:00 |显示全部楼层
还是慎重使用scanf,尤其是字符串时,可能越界的!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP