From: "John M. Aldrich" 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: Reply-To: fighteer AT cs DOT com NNTP-Posting-Host: ppp108.cs.com Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit To: Chris Frolik 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 > > 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 #include /* needed for atol() */ #include /* 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 | ---------------------------------------------------------------------