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()常犯错误

posted @ 2015-07-10 13:38  oucaijun  阅读(11900)  评论(0编辑  收藏  举报
下载TeamViewer完整版 下载TeamViewer