[comp.lang.c] problems with scanf

spm2d@watt1.acc.Virginia.EDU (Steven Paul Miale) (10/12/90)

I have received many replies to my question about the safety of using
scanf() in a program, including one flame, remarkably. I have decided
to post the answers (overwhelmingly anti-scanf(), BTW). Keep in mind
that this "survey" is not big enough to be judged accurate. However,
I would still be cautious about using scanf() until then.

First, the flame, just received:

Date: Fri, 5 Oct 90 11:37:16 -0500
From: Judge Dredd <bob@en.ecn.purdue.edu>
Message-Id: <9010051637.AA21255@en.ecn.purdue.edu>
To: spm2d@watt1.acc.virginia.edu
Subject: Re: scanf() problems
Newsgroups: comp.lang.c
In-Reply-To: <1990Oct4.130831.7814@murdoch.acc.Virginia.EDU>
Organization: Purdue University Engineering Computer Network
Status: RO

In article <1990Oct4.130831.7814@murdoch.acc.Virginia.EDU> you write:
>Recently, I have heard that many implementations of C have a buggy version
...
>Please E-mail me, as I usually do not keep up with this newsgroup.

Ever think that after taking the time to read your question that some
of us might like to SEE THE ANSWERS?!?!

Ever think how rude it is to jump into a group, tell it you want to use
its resources, and then add that you won't be around long enough to read
the answer, so you'll be sucking all the replies into your mailbox where
only you can read them?

Ever think that most of the people that read the group don't even post?
They simply read the group to LEARN?  Ever think that this learning is
from reading people's questions and the POSTED replies?

I understand how you might not have the time or whatever to read the
group.  No problem.  So what's the solution?  Well, if you look at any
of the "netiquette" files floating around you'll see that the "proper"
B
thing to do in cases like this is to ask your question, request email,
and ANNOUNCE IN THE ORIGINAL POSTING that you will be posting a summary
in a week or whatever.  And then do it.  Also, you should keep ALL replies
in a file for a reasonable amount of time and email that file to anyone
who requests it.


-- 
Bob Rusbasan
bob@en.ecn.purdue.edu

<ahem>. Now, some real answers:

From: tanner@cdis-1.compu.com
To: spm2d@watt1.acc.virginia.edu
Subject: Re: scanf() problems
Newsgroups: comp.lang.c
In-Reply-To: <1990Oct4.130831.7814@murdoch.acc.Virginia.EDU>
Organization: CompuData, Inc. (DeLand)
X-Snail: 1409 E New York Ave; DeLand, FLA   32724.
X-Phone: +1 904 736 0866
Message-Id: <00002CB@cdis-1.compu.com>
Status: RO

Even a working scanf() is bad news; avoid it like the plague.  It
does a poor job of coping with bad input, and will surely confuse
interactive users.

Use fgets() or something, and parse the input yourself.  Even using
sscanf() on the fgets()ed input is far better than using scanf().
-- 
uflorida!ki4pv!cdis-1!tanner {uunet dsinc}!cdin-1!cdis-1!tanner

To: Steven Paul Miale <spm2d@watt1.acc.virginia.edu>
Subject: Re: scanf() problems
From: "Roy M. Silvernail" <cybrspc!roy@cs.umn.edu>
Message-Id: <moHLq1w163w@cybrspc>
Date: Fri, 05 Oct 90 19:53:57 CDT
In-Reply-To: <1990Oct4.130831.7814@murdoch.acc.Virginia.EDU>
Organization: Villa CyberSpace, Minneapolis, MN
Status: RO

spm2d@watt1.acc.Virginia.EDU (Steven Paul Miale) writes:

> Recently, I have heard that many implementations of C have a buggy version
> of scanf() attached which may cause a hard drive crash; these assertations
> are from the famous C authorities here in Charlottesville.
> They also claim that most scanf() versions are buggy, and to use other
> read commands (such as gets() ) or to write your own routines.
> Is there any truth to this rumor? I have repeatedly told these few
> not to blast all versions of C because a few may have bad implementations,
> but they keep pestering me and I want some *real* C programmers to set
> it straight.
> Please E-mail me, as I usually do not keep up with this newsgroup.
> ---
> Steven Miale
> spm2d@virginia.edu

While I haden't heard of scanf() crashing a disk, I still never use it.
The reason is that scanf() expects input to be formatted properly, and
you cannot guarantee that a user will not make a mistake. Input routines
should always, IMHO, read to a buffer and _validate the inputted data_.
At the least, a scanf() call may return unexpected data and/or leave
unread data in the stdin buffer. At worst, data read may overwrite the
end of an array and cause no end of havoc. 'Tis much safer to gets(),
validate the string returned, and sscanf() the string.
--
    Roy M. Silvernail   | #include <stdio.h>                 | Does virtual
    now available at:   | main(){                            | reality need
 cybrspc!roy@cs.umn.edu |  float x=1;                        | swap space?
(cyberspace... be here!)|  printf("Just my $%.2f.\n",x/50);} | -- me
B
From: Dave Eisen <dkeisen@gang-of-four.stanford.edu>
Message-Id: <9010050530.AA25480@Gang-of-Four.Stanford.EDU>
To: spm2d@watt1.acc.virginia.edu
Subject: Re: scanf() problems
Newsgroups: comp.lang.c
In-Reply-To: <1990Oct4.130831.7814@murdoch.acc.Virginia.EDU>
Organization: Sequoia Peripherals
Cc:  
Status: RO

Even if scanf works, it doesn't work. You never want to use it because
if the user doesn't happen to enter a statement that matches the correct
format, scanf doesn't react intelligently. Uses gets and then sscanf
the buffer you read into.



-- 
Dave Eisen                      	    Home: (415) 323-9757
dkeisen@Gang-of-Four.Stanford.EDU           Office: (415) 967-5644
1447 N. Shoreline Blvd.
Mountain View, CA 94043

Reply-To: Stephen Clamage <steve@taumet.com>
Message-Id: <9010051513.AA02049@taumet.com>
Date: Fri, 5 Oct 90 15:13:07 GMT
From: Stephen Clamage <steve@taumet.com>
X-Local-Time: Fri, 5 Oct 90 08:13:07 PDT
To: spm2d@watt1.acc.virginia.edu
Subject: Re: scanf() problems
Newsgroups: comp.lang.c
References: <1990Oct4.130831.7814@murdoch.acc.Virginia.EDU>
Status: RO

In comp.lang.c you write:

>Recently, I have heard that many implementations of C have a buggy version
>of scanf() attached which may cause a hard drive crash; these assertations
>are from the famous C authorities here in Charlottesville.
>They also claim that most scanf() versions are buggy, and to use other
>read commands (such as gets() ) or to write your own routines.

Floating-point conversion routines in most C libraries tend not to be
very good, since they are not usually written by numerical analysts.
Unless you have an excellent reference, are a trained numerical analyst,
or have a very restricted set of possible values to contend with,
you may not be able to do any better.  "Sigplan Notices", vol 25, No 6,
June 1990, contains a pair of articles describing how to read and write
floating-point values.  It is hard to get right.

I have never heard of scanf crashing a hard drive, but then I don't
use scanf much -- actually never, except in throw-away test programs.
Scanf does not give you proper control over reading input data produced
by humans, which is full of weird typos and other errors.  It does not
give any good recovery mechanism when errors are encountered.  It is
generally clunky and error-prone to use (the most common error is
to use the %f conversion to read a value into a double).

If your C library has good implementations of strtoi(), strtol(), and
strtod(), you can make a more robust program using these plus character
input routines such as you describe.  If you want a quick-and-dirty
throw-away program, scanf should suffice if it doesn't trash your disk.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

From: Richard Bumby <bumby@math.rutgers.edu>
Message-Id: <9010051926.AA17708@math.rutgers.edu>
To: spm2d@watt1.acc.virginia.edu
Cc: bumby@math.rutgers.edu
Subject: Re: scanf() problems
In-Reply-To: USENET article <1990Oct4.130831.7814@murdoch.acc.Virginia.EDU>
Status: RO

In article <1990Oct4.130831.7814@murdoch.acc.Virginia.EDU> you wrote:

> They also claim that most scanf() versions are buggy, and to use other
> read commands (such as gets() ) or to write your own routines.
> Is there any truth to this rumor? 

I'm not a real C programmer, but I have used Whitesmith's C for an
MC68000 based machine and Manx Aztec-C for the IBMPC.  In both cases,
there is more than one version of formatted I/O included in the
libraries, and the two versions have different behavior in identical
situations. It seems to be difficult to get this right.  The main
reason for using scanf() is to have a single function to use during
development so that you don't have to think about I/O.  You can
usually learn the one or two strange features of the version that you
have. Once you know what kind of input to expect, you will do much
better with a customized interface -- and you can be reasonably sure
that it will be portable, too.
--

--R. T. Bumby ** Math ** Rutgers ** New Brunswick ** NJ08903 ** USA --
  above postal address abbreviated by internet to bumby@math.rutgers.edu
  voice communication unreliable -- telephone ignored -- please use Email

Date: Fri, 5 Oct 90 18:10:52 EDT
From: Larry Jones <sdrc!scjones%thor@uunet.uu.net>
Message-Id: <9010052210.AA00032@thor>
To: uunet!watt1.acc.Virginia.EDU!spm2d@uunet.uu.net
Subject: Re: scanf() problems
In-Reply-To: your article <1990Oct4.130831.7814@murdoch.acc.Virginia.EDU>
News-Path: sdrc!uunet!know!zaphod.mps.ohio-state.edu!wuarchive!udel!haven!uvaarpa!murdoch!watt1.acc.Virginia.EDU!spm2d
Status: RO

> Recently, I have heard that many implementations of C have a buggy version
> of scanf() attached which may cause a hard drive crash; these assertations
> are from the famous C authorities here in Charlottesville.
> They also claim that most scanf() versions are buggy, and to use other
> read commands (such as gets() ) or to write your own routines.
> Is there any truth to this rumor? I have repeatedly told these few
> not to blast all versions of C because a few may have bad implementations,
> but they keep pestering me and I want some *real* C programmers to set
> it straight.

I think you need some new C authorities. ;-)

Most versions of scanf work just fine, although they do not all agree
on all of the finer and more obscure details of formatting.  On the
other hand, scanf is deceptively easy to use and nearly impossible to
use in a completely correct and robust manner, which has lead many
people to recommend using a combination of fgets and sscanf instead
of scanf.  Perhaps that was the point your local experts were trying
to make.
----
Larry Jones                         UUCP: uunet!sdrc!thor!scjones
SDRC                                      scjones@thor.UUCP
2000 Eastman Dr.                    BIX:  ltl
Milford, OH  45150-2789             AT&T: (513) 576-2070
I don't like these stories with morals. -- Calvin

ttobler@unislc.uucp (Trent Tobler) (10/20/90)

[many comments on the evils of scanf]

People, scanf is not BAD, only people who use it as their primary input
function.  Scanf is a very powerful pattern matching function and can
save a lot of code in parsers and tokenizers.  

I think the main reason everyone is anti-scanf is that in many languages,
there is a primary input function (readln, input, etc.), and scanf is
often assigned this purpose by many C programming classes/tutorials.
This is the reason that many of the problems of scanf are encountered.
I believe that scanf should be taught only after a strong knowlegde in C
is attained.  The gets function should be used as the beginning primary
input function.  Later, when files are learned, this should switch to fgets,
to avoid the problem of overflow allocated string space.  Scanf should not
ever be considered a primary input function.  Use it to parse, and match
patterns from the input stream.

I think most people who abhore scanf have been told by other people that scanf
is EVIL.  More than likely, it was after a catastrophic failure from thier use
of it as a primary input function.

Improper use can cause infinite loops, lockups, and core dumps.
But, on the other side, scanf is a very powerful tool .  It can reduce time
to develop a program, reduce code size, and even make a program more
maintainable.



         Trent Tobler.

donn@brat.UUCP (Donn Pedro) (10/26/90)

In article <1990Oct20.001637.28244@unislc.uucp>, ttobler@unislc.uucp (Trent Tobler) writes:
> 
> [many comments on the evils of scanf]
> 
> People, scanf is not BAD, [ rest of the sensible talk deleted for brevity.]

We discussed scanf() in my C course today.  The insructor basically said
to be cautious of scanf() but not fearful to use it.  He said it can be
a very useful and powerful tool *as long as* you understand it's 
limitations and foibles.

To paraphrase:

	Commnads don't kill data.  People kill data.


      Donn F Pedro ....................a.k.a. uunet!nwnexus!mcgp1!brat!donn
         else:  {the known world}!uunet!nwnexus!mcgp1!brat!donn 

poser@csli.Stanford.EDU (Bill Poser) (10/28/90)

I don't see why it is necessary to worry about scanf(). It is safe to use
directly only when you are quite sure of the input format, which is not
very often. But you can use its parsing facilities safely by reading
input using a safe getline function (I often use one that strips
comments and allows quoting of newlines in place of one that merely
counts input characters to prevent overflowing the buffer) and then
using sscanf(). Except for one-shot programs I suggest avoiding fscanf()
altogether and using sscanf plus a safe input function.

adrian@mti.mti.com (Adrian McCarthy) (10/30/90)

The VAX C 3.0 library version of sscanf() doesn't handle unsigned values at
all (according to the docs).  In particular I needed a text to unsigned long
conversion.  I used the strtoul() function, but I was wondering if anyone
knows if 3.1 added this functionality to sscanf().

Also, does Henry Spencer's commandment about checking the return values of all
functions for errors apply to sscanf()?  Since sscanf() is supposed to return
the number of successful conversions, it seems reasonable to do things like:

  if (sscanf(str, "%d %d", &x, &y) != 2) {
    fprintf(stderr, "Error parsing string.\n");
    exit(PARSE_ERROR);
  }

Right?

Aid.  (adrian@gonzo.mti.com)

henry@zoo.toronto.edu (Henry Spencer) (10/31/90)

In article <1204@mti.mti.com> adrian@mti.UUCP (Adrian McCarthy) writes:
>Also, does Henry Spencer's commandment about checking the return values of all
>functions for errors apply to sscanf()? ...
>  if (sscanf(str, "%d %d", &x, &y) != 2) {

So long as you are checking the return value, and not just blindly assuming
that sscanf will work, that satisfies the intent of the commandment.
-- 
"I don't *want* to be normal!"         | Henry Spencer at U of Toronto Zoology
"Not to worry."                        |  henry@zoo.toronto.edu   utzoo!henry

msb@sq.sq.com (Mark Brader) (11/07/90)

> ... it seems reasonable to do things like:
>   if (sscanf(str, "%d %d", &x, &y) != 2) {
>     fprintf(stderr, "Error parsing string.\n");
>     exit(PARSE_ERROR);
>   }

Sure.  But don't imagine that you've checked the syntax of the string
by doing that.  If it's supposed to contain precisely two numbers and
nothing else, one way to do it is:

    char junk;
      ...
    if (sscanf(str, "%d %d%c", &x, &y, &junk) != 2) {
      fprintf(stderr, "Error parsing string.\n");
      exit(PARSE_ERROR);
    }

If there is anything after the second number, sscanf() will now
return 3.  Notice incidentally that this is one of the few places where
it's reasonable in C to have a scalar variable of type char.  Normally
time efficiency is more important than space efficiency for scalars,
so you use int, but here the address of the variable must be char *
to match the %c directive, and you aren't going to read from it anyway.

-- 
Mark Brader			"Exercise 5-3: ... When should you
SoftQuad Inc., Toronto		 have stopped adding features...?"
utzoo!sq!msb, msb@sq.com				-- Kernighan & Pike

This article is in the public domain.

jhp@apss.ab.ca (Herbert Presley) (06/06/91)

I am a new C programmer and I've been trying to get an answer through the net 
for the following problem.  Unfortunately, my postings don't seem to be getting
through for some reason.

I kinda feel intimidated because, like most new programmers, I am probably
asking a question that has a VERY simple response, and I can't help but feel
that it's a problem that I am creating by my lack of knowledge.

For your information, I run a Turbo C compiler on an XT (true) compatible.

scanf() and gets() will not accept keyboard input in the same program if
scanf() is used first.  I am using scanf() to accept an integer from the
keyboard and gets() to accept a string.  Because scanf() aborts input at
the first whitespace, you cannot enter a sentence string (or, is this something
I am doing wrong because of my inexperience)?  So in instances where you are
attempting to enter a formatted integer variable and a string in the same
program, I find that using scanf() first makes gets() skip the wait for
keyboard input.

Unfortunately, I have no mentor in my world who knows very much about C.  I
began with C through a couple of courses at our local Technical College and
they don't seem to offer a great deal of ongoing support.
___________________________________________________________________________

    email : jhp@apss.ab.ca 
     mail : c/o APSS, 10320 - 146 St., Edmonton, Alberta, Canada  T5N 3A2 
    phone : (403) 451-7151

gordon@osiris.cso.uiuc.edu (John Gordon) (06/07/91)

jhp@apss.ab.ca (Herbert Presley) writes:

>scanf() and gets() will not accept keyboard input in the same program if
>scanf() is used first.  I am using scanf() to accept an integer from the
>keyboard and gets() to accept a string.  Because scanf() aborts input at
>the first whitespace, you cannot enter a sentence string (or, is this something
>I am doing wrong because of my inexperience)?  So in instances where you are
>attempting to enter a formatted integer variable and a string in the same
>program, I find that using scanf() first makes gets() skip the wait for
>keyboard input.

	Here is your problem: scanf() leaves a carriage return hanging in the
input buffer.  Since gets() ends on a carriage return, it picks this up
immediately and quits.  My solution is to do a getchar() right after a scanf()
and suck up the floating carriage return.

---
John Gordon
Internet: gordon@osiris.cso.uiuc.edu        #include <disclaimer.h>
          gordon@cerl.cecer.army.mil       #include <clever_saying.h>

darwinl@alliance.uucp (Darwin Ling) (06/07/91)

In article <2759@apss.apss.ab.ca> jhp@apss.ab.ca (Herbert Presley) writes:
>
>I am a new C programmer and I've been trying to get an answer through the net 
>for the following problem.  Unfortunately, my postings don't seem to be getting
>through for some reason.
>
>I kinda feel intimidated because, like most new programmers, I am probably
>asking a question that has a VERY simple response, and I can't help but feel
>that it's a problem that I am creating by my lack of knowledge.
>
>For your information, I run a Turbo C compiler on an XT (true) compatible.
>
>scanf() and gets() will not accept keyboard input in the same program if
>scanf() is used first.  I am using scanf() to accept an integer from the
>keyboard and gets() to accept a string.  Because scanf() aborts input at
>the first whitespace, you cannot enter a sentence string (or, is this something
>I am doing wrong because of my inexperience)?  So in instances where you are
>attempting to enter a formatted integer variable and a string in the same
>program, I find that using scanf() first makes gets() skip the wait for
>keyboard input.
>
>Unfortunately, I have no mentor in my world who knows very much about C.  I
>began with C through a couple of courses at our local Technical College and
>they don't seem to offer a great deal of ongoing support.
>___________________________________________________________________________
>
>    email : jhp@apss.ab.ca 
>     mail : c/o APSS, 10320 - 146 St., Edmonton, Alberta, Canada  T5N 3A2 
>    phone : (403) 451-7151


You can try the following :

   Use fgets to get whatever from the standard input....

   For string, if the last string character is a '\n' , ie a newline
   character, replace it with '\0'. You can find the last character's
   position by strlen (str) - 1 . 

   For integer , do the same thing to eliminate the '\n' , then 
   convert the integer string to integer using 

   sscanf (str, "%d", &integer_value)

   str is the string you get from fgets.. 
   sscanf works exactly the same as scanf except sscanf scans from a string,
   while scanf scans its input from the standard input...
   You can use the desired format for the integer

   Hope that helps


------------------------------------------------------------------
				Darwin Ling                       

				Alliance Technologies , Inc
				Advanced Development group
				uunet :     uunet!alliance!darwinl
------------------------------------------------------------------

black@beno.CSS.GOV (Mike Black) (06/07/91)

NEVER USE THESE FUNCTIONS!

1. scanf() and fscanf() - if you don't input the EXACT format you
are scanning for, your input stream will no proceed any further.
i.e. scanf("%d",&i) will stop when you type "hello" and will
not scan blasted thing until you read in the hello with another
function.

2. gets() - It doesn't check to make sure you don't overrun the 
char array you pass it.

INSTEAD USE THESE!

1. fgets() followed by sscanf()  - This gives you complete control
over your input stream by allowing you to discard garbage.  i.e.

char buf[100];
fgets(buff,100,stdin);
if(sscanf(buf,"%d",&i) != 1) puts("You typed the wrong thing!");

2. fgets() - it's the same as gets with 2 more arguments, the
main one of which is the maximum length of your array.

One of the other benefits of using fgets() and sscanf() on numeric
input is it's generally quite faster than fscanf().  Try it!
Mike...
--
-------------------------------------------------------------------------------
: usenet: black@beno.CSS.GOV   :  land line: 407-494-5853  : I want a computer:
: real home: Melbourne, FL     :  home line: 407-242-8619  : that does it all!:
-------------------------------------------------------------------------------

darcy@druid.uucp (D'Arcy J.M. Cain) (06/07/91)

In article <1991Jun6.182118.16211@ux1.cso.uiuc.edu> John Gordon writes:
>jhp@apss.ab.ca (Herbert Presley) writes:
>>scanf() and gets() will not accept keyboard input in the same program if
  [ description of the usual scanf/gets problem deleted ]
>	Here is your problem: scanf() leaves a carriage return hanging in the
>input buffer.  Since gets() ends on a carriage return, it picks this up
>immediately and quits.  My solution is to do a getchar() right after a scanf()
>and suck up the floating carriage return.

Actually he has two problems.  First he didn't read the FAQ and secondly
he is getting advice from people who haven't read the FAQ.  Here is the
definitive answer:

              READ THE FREQUENTLY ASKED QUESTIONS

In particular question #77 answers this:

77.  When I read from the keyboard with scanf(), it seems to hang until
     I type one extra line of input.

A:   scanf() was designed for free-format input, which is seldom what
     you want when reading from the keyboard.  In particular, "\n" in a
     format string does not mean "expect a newline", it means "discard
     all whitespace".

     It is usually better to fgets() to read a whole line, and then use
     sscanf() or other string functions to parse the line buffer.

If you are going to answer questions please read the FAQ first.  This is
also excellent advice before asking one.

-- 
D'Arcy J.M. Cain (darcy@druid)     |
D'Arcy Cain Consulting             |   There's no government
Toronto, Ontario, Canada           |   like no government!
+1 416 424 2871                    |

crr@cbnewsm.att.com (Chris Riley (201) 564-2516) (06/08/91)

In article <2759@apss.apss.ab.ca> jhp@apss.ab.ca (Herbert Presley) writes:
>I kinda feel intimidated because, like most new programmers, I am probably
>asking a question that has a VERY simple response, and I can't help but feel
>that it's a problem that I am creating by my lack of knowledge.

That's ok.  That's what stuff like comp.lang.c is for.

>scanf() and gets() will not accept keyboard input in the same program if
>scanf() is used first.  I am using scanf() to accept an integer from the
>keyboard and gets() to accept a string.  Because scanf() aborts input at
>the first whitespace, you cannot enter a sentence string (or, is this something
>I am doing wrong because of my inexperience)?  So in instances where you are
>attempting to enter a formatted integer variable and a string in the same
>program, I find that using scanf() first makes gets() skip the wait for
>keyboard input.

It is generally unsafe to use scanf() to read from the keyboard.  Since
scanf() will loose data if the data isn't formatted the way it likes, it is
dangerous to use scanf() unless the data you are reading was generated by
another program.

A safer method is to read a string with gets() or fgets(), then use
sscanf() to look for the data in the string.  If the data isn't in the
right format, you have a chance to try to figure out what it is.

-- 
Chris Riley            chris.riley@attbl.att.com

naftaly@dazixco.ingr.com (Naftaly Stramer) (06/13/91)

Where can I find those Frequently Asked Questions ?
-- 
Naftaly Stramer (303)581-1477                  DAZIX, An Intergraph Company
Internet: naftaly@dazixco.ingr.com             6285 Lookout Road    
UUCP: ..uunet!ingr!dazixco!naftaly  	       Boulder, CO 80301
Please excuse my english