www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1996/11/13/22:06:27

From: "John M. Aldrich" <fighteer AT cs DOT com>
Newsgroups: comp.os.msdos.djgpp
Subject: Re: newbie needs help
Date: Wed, 13 Nov 1996 21:07:40 -0800
Organization: Three pounds of chaos and a pinch of salt
Lines: 152
Message-ID: <328AA91C.4505@cs.com>
References: <frolikcc-1311962003140001 AT indynet DOT indy DOT net>
Reply-To: fighteer AT cs DOT com
NNTP-Posting-Host: ppp108.cs.com
Mime-Version: 1.0
To: Chris Frolik <frolikcc AT indy DOT net>
To: djgpp AT delorie DOT com
DJ-Gateway: from newsgroup comp.os.msdos.djgpp

Chris Frolik wrote:

All this information can be learned from a basic C textbook.  I suggest
you shop around for one, because for a rank beginner there's a LOT you
need to learn.  For a brief discussion, read on...

> #include <stdio.h>
> 
> void main()
> {
>    long n=0, x=0, result=0;
>    printf("\n Enter a number between 1 and 100: ");
>    scanf("%ld", &x);
>    printf("\n Enter another number between 1 and 100: ");
>    scanf("%ld", &n);
> 
>    result = x - n;
>    printf("%ld - %ld = %ld", x, n, result);
> }
> 
> So, I compiled it and ran it. It worked fine, unless I entered a decimal
> (i.e. .6) or a letter at the first prompt.  If I did, it skipped the
> second scanf() entirely.  Is this supposed to happen?  I have no
> experience with this, so I am not sure.  If so, what can I do to prevent
> it?

Yes, this is supposed to happen.  Scanf() reads from input until it
finds a terminating character, and then it stops.  For an integer, any
non-integer value is a terminating character, so the '.' in ".6" causes
it to stop reading.  However, that '.' is still in the input buffer and
gets read by the next scanf(), which doesn't like it either, and returns
without giving you a value for n.

There are a couple of solutions to your problem.

1) Read a float number in (with %f) and convert it to an integer.  Quick
and dirty, but still error-prone.

2) Check the return value of scanf().  Scanf() returns an integer
telling you how many values it successfully read, so if it returns a
zero (or anything less than the number of inputs expected), you can
catch this and so inform the user.  This is not perfect because it
doesn't catch input errors until the input _after_ the erroneous one. 
Also, there is a small bug in the *scanf() code that only manifests
itself when reading from text files; if you have DJGPP v2.01, this bug
is fixed.

3) Flush the input buffer after each call to scanf().  Something as
simple as "while ( getchar( ) != '\n' );" will do the trick.  If using
#2 above, you still have to do this.  This works well, but doesn't trap
erroneous input.  (i.e., if your user types "xyz" at the input prompt, x
will never get read in and will contain garbage.)

4) Use gets() (or better, fgets) to read one line at a time, and then
read the first value from that line using sscanf().  In addition to
this, you can scan the line for non-numeric characters and ask for
reinput if any were found.

How would I do this?  The following is a bit complex, but illustrates
most of the pitfalls you can encounter in user input.  Actually, I would
do a few other things too, but this illustrates the basic point.  Note
that I use a function to handle getting the input - this is good
programming technique.  :)

---- cut here ----

#include <stdio.h>
#include <stdlib.h>		/* needed for atol() */
#include <ctype.h>		/* needed for isdigit() */

void getnumber( const char *, long * );  /* function declaration */

int main( void )   		/* main MUST return an int!! */
{
    long n, x, result;		/* no need to initialize; in fact     */
				/* it's better not to so the compiler */
				/* can catch you if you forget to     */
				/* assign a variable a value	      */

    printf( "\n" );
    getnumber( "Enter a number between 1 and 100: ", &n );
    printf( "\n" );
    getnumber( "Enter another number between 1 and 100: ", &x );
 
    result = x - n;
    printf("%ld - %ld = %ld", x, n, result);

    return 0;  			/* program exited successfully */
}

void getnumber( const char *prompt, long *pnum )
{
    char line[256];		/* holds input line */
    int i;

    while ( 1 )			/* 1 = true; runs until stopped */
    {
        printf( prompt );
        gets( line );		/* gets reads one line from stdin */

	/* Examine input.  If we hit a non-numeric character, stop. */
        for ( i = 0; line[i]; i++ )
            if ( !isdigit( line[i] ) )
                break;

	/* If a number was entered, i will be at the end of line.
	   Also, if i == 0, nothing at all was entered. */
        if ( i > 0 && line[i] == '\0' )
            break;

        printf( "Please enter only one non-decimal integer.\n" );
    }

    *pnum = atol( line );  /* turn the string into a number, and put
			      it into the memory pointed to by pnum */
    return;
}

---- cut here ----

> Also - when printing a float, how can I drop off the trailing zeros?  For
> example, if i have:
> 
>    float x=2.5;
>    printf("%f", x);
> 
> It prints out 2.500000, while I only want it to print 2.5.

Use the standard modifiers to printf formats, which can be found by
looking up printf() in the documentation.  In DJGPP, simply type "info
libc alpha printf" from the DOS prompt (assuming you installed
'txi390b.zip' of course).

In short, use this format:

printf( "%3.1f", x );

3 is the total field length, counting the decimal and fractional
portion, and .1 is the precision.  If you don't want the value in a
"field", you can omit the 3 and just use "%.1f".

As a final note, main() must always return an int - it's required to do
so by the ANSI C specification.  Don't neglect this because some
ignorant book or teacher told you to (and there are a LOT of them out
there).

-- 
---------------------------------------------------------------------
| John M. Aldrich, aka Fighteer I |        fighteer AT cs DOT com          |
| Proud owner of what might one   |   http://www.cs.com/fighteer    |
| day be a spectacular MUD...     | Plan: To make Bill Gates suffer |
---------------------------------------------------------------------

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019