[comp.lang.c] C Quirk??

dmg@ssc-vax.UUCP (David Geary) (02/04/88)

I've been wondering about this for a long time.  Maybe someone out there
can shed some light on the subject...

#include <stdio.h>
#include <ctype.h>

main()
{
  char ch;

  puts("Enter a Character:  ");

  while( (ch = getchar()) )
  {
    if( isupper(ch) )
      tolower(ch);

    printf("%c\n", ch);
    puts("Enter a Character:  ");
  }
}

Here's the output that I get when running the above program:

Enter a Character:
a
A
Enter a Character:


Enter a Character:


The first time, everything is ok.  The next time, however, it seems
to just blow right by the getchar().

This is what I think:

It asks me to "Enter a Character:  ".  I type 'a', and then a newline.
getchar() grabs the 'a' from stdin, but leaves the newline hanging.
The next time getchar() comes around, it grabs the newline that was
left hanging around last time.

Note that if I insert fflush(stdin) before I do if( isupper(ch) ),
everything works correctly.

Is this a *bug* in C, or is it a *feature*.  Am I interpreting events
correctly?  Is there a fix besides fflush()?

I love to program in C, but this p*sses me off.  Thanks in advance
for the replies.


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~	"...You can't always get what you want..."	~
~			Rolling Stones			~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


-- 
***********************************************************
* David Geary, Boeing Aerospace Co., Seattle, WA 	  *
* (206)773-5249.  --I disclaim everything I've ever said--*
***********************************************************

edw@IUS1.CS.CMU.EDU (Eddie Wyatt) (02/05/88)

Not that this requires a net response, I just like reading my posts :-)


> 
> #include <stdio.h>
> #include <ctype.h>
> 
> main()
> {
>   char ch;
> 
>   puts("Enter a Character:  ");
> 
>   while( (ch = getchar()) )
>   {
>     if( isupper(ch) )
>       tolower(ch);
> 
>     printf("%c\n", ch);
>     puts("Enter a Character:  ");
>   }
> }


  You must also read the carriage return.  When you type a<return>
There are two character out there for you to read, not just one
as you might have thought - "a\n".

   There are a couple of approaches to deal with this.  One OS
depended would be to read characters as soon as they are typed,
hence not requiring the user to type a return.  Another probably
more applicatable, would be to clear the input line after reading.

#define		clearline()		while (getchar() != '\n')
.
.
.
ch = getchar();
clearline();
.
.
.
-- 

Eddie Wyatt 				e-mail: edw@ius1.cs.cmu.edu

mrd@sun.soe.clarkson.edu (Mike DeCorte) (02/05/88)

In article <1653@ssc-vax.UUCP> dmg@ssc-vax.UUCP (David Geary) writes:

   It asks me to "Enter a Character:  ".  I type 'a', and then a newline.
   getchar() grabs the 'a' from stdin, but leaves the newline hanging.
   The next time getchar() comes around, it grabs the newline that was
   left hanging around last time.

   Note that if I insert fflush(stdin) before I do if( isupper(ch) ),
   everything works correctly.

   Is this a *bug* in C, or is it a *feature*.  Am I interpreting events
   correctly?  Is there a fix besides fflush()?

First off. You have the line
      tolower(ch);
in your text as a statement.  This does nothing.  tolower()
(as well as all of the things in ctype.h) return values.  In
this case it returns the lower case of ch but ch itself is not
modified.

second:
You are 100% correct on what C is doing with your input.
You see getchar gets ONE character, not one character and a
'\n'.  The first call grabs 'C' the second call grabs '\n'.
The logical response to this is "well how do I tell this
thing that I don't want to type return?"  What the tty driver
is doing is buffering your I/O.  To turn off buffering
is well system dependent.  On unix one uses ioctl(2) on 
anything else - I don't know.  

-- 

Michael DeCorte // mrd@clutx.clarkson.edu // mrd@clutx.bitnet
(315)268-4704 // P.O. Box 652, Potsdam, NY 13676

kurt@hi.unm.edu (Kurt Zeilenga) (02/06/88)

In article <804@PT.CS.CMU.EDU> edw@IUS1.CS.CMU.EDU (Eddie Wyatt) writes:
>Not that this requires a net response, I just like reading my posts :-)
>
>#define		clearline()		while (getchar() != '\n')
>ch = getchar();
>clearline();
>Eddie Wyatt 				e-mail: edw@ius1.cs.cmu.edu

If you want to read the whole line (like for a command line parser),
then I would suggest using fgets() or gets() and then using scanf to
grab out whatever you wanted.  Examples? try K&R.
-- 
	Kurt (zeilenga@hc.dspo.gov)

jsp@sp7040.UUCP (John Peters) (02/10/88)

In article <1653@ssc-vax.UUCP>, dmg@ssc-vax.UUCP (David Geary) writes:
> 
> I've been wondering about this for a long time.  Maybe someone out there
> can shed some light on the subject...
> 
> #include <stdio.h>
> #include <ctype.h>
> 
> main()
> {
>   char ch;
> 
>   puts("Enter a Character:  ");
> 
>   while( (ch = getchar()) )
>   {
>     if( isupper(ch) )
>       tolower(ch);
> 
>     printf("%c\n", ch);
>     puts("Enter a Character:  ");
>   }
> }
> 
> Here's the output that I get when running the above program:
> 
> Enter a Character:
> a
> A
> Enter a Character:
> 
> 
> Enter a Character:
> 
> 
> The first time, everything is ok.  The next time, however, it seems
> to just blow right by the getchar().
> 

This does indead leave the newline in the buffer.  I no of several ways to
get around the problem.  Probabley the easiest (and it can also save a lot
of other hastles) is:

#include <stdio.h>
#include <ctype.h>

#define EVER (;;)

main()
{
    char	a[5];

    for EVER {
	gets (a);
	printf ("%c\n", toupper (a[0]));
    }
}

This gets ride of certain other evils such as accidentally entering more than
one character.

Also you can use the standard scanf botch to do it.

	scanf ("%c%*c", a);  

This tells the program to skip the next character after reading one.

Since it sounds like you are wanting just one character at a time how about
considering putting the system in raw mode so that when you do the getchar
it comes right back at you.  Why wait an force the user to hit a charrage
return.

					--  John  --

	{backbones}!ihnp4!utah-cs!utah-gr!uplherc!sp7040!jsp

	DISCLAIMER:  My spelling is my own and boy does the company hate it!

chip@ateng.UUCP (Chip Salzenberg) (02/12/88)

In article <804@PT.CS.CMU.EDU> edw@IUS1.CS.CMU.EDU (Eddie Wyatt) writes:
>
>#define               clearline()             while (getchar() != '\n')

This is seriously bad code.  What if stdin reaches end of file?

-- 
Chip Salzenberg                 UUCP: "{codas,uunet}!ateng!chip"
A T Engineering                 My employer's opinions are a trade secret.
       "Anything that works is better than anything that doesn't."

greywolf@unicom.UUCP (Caesar's Palace morning glory, silly human race.) (02/16/88)

In article <1653@ssc-vax.UUCP> dmg@ssc-vax.UUCP (David Geary) writes:
# 
# I've been wondering about this for a long time.  Maybe someone out there
# can shed some light on the subject...
# 
# #include <stdio.h>
# #include <ctype.h>
# 
# main()
# {
#   char ch;
# 
#   puts("Enter a Character:  ");
# 
#   while( (ch = getchar()) )
#   {
#     if( isupper(ch) )
#       tolower(ch);
# 
#     printf("%c\n", ch);
#     puts("Enter a Character:  ");
#   }
# }
# 
# Here's the output that I get when running the above program:
# 
# Enter a Character:
# a
# A
# Enter a Character:
# 
# 
# Enter a Character:
# 
# 
# The first time, everything is ok.  The next time, however, it seems
# to just blow right by the getchar().
# 
# This is what I think:
# 
# It asks me to "Enter a Character:  ".  I type 'a', and then a newline.
# getchar() grabs the 'a' from stdin, but leaves the newline hanging.
# The next time getchar() comes around, it grabs the newline that was
# left hanging around last time.
# 
# Note that if I insert fflush(stdin) before I do if( isupper(ch) ),
# everything works correctly.
# 
# Is this a *bug* in C, or is it a *feature*.  Am I interpreting events
# correctly?  Is there a fix besides fflush()?
# 
# I love to program in C, but this p*sses me off.  Thanks in advance
# for the replies.

Have you tried inserting the following:

*** what_was_here ***
--- my_additions ---

*** if( isupper(ch) )
***   tolower(ch);
*** printf("%c\n", ch);
--- while (getchar() != '\n')
---	;
*** puts("Enter a Character: ");
*** }
...

That oughtta work, given it's expecting the newline after a character is
entered anyway.  If you want to interpret newlines as well, you're going to
have to settle for cbreak or raw mode for input.


Hope that helped,

Roan.

-- 
 " <- (2 dots)		    ::   / | \ ...!{sun,ucbvax}!pixar!unicom!greywolf
Roan Anderson, Local Guru   ::  :  |  :
(which doesn't say much)    ::  : /|\ : war: Invalid argument.
:::::::::::::::::::::::::::::::: =_|_=  ::::::::::::::::::::::::::::::::::::::

edw@IUS1.CS.CMU.EDU (Eddie Wyatt) (02/17/88)

> >
> >#define               clearline()             while (getchar() != '\n')
> 
> This is seriously bad code.  What if stdin reaches end of file?
> 

   It loops forever -- oops.  Change that to 

#define clearline() while (1) {int ch = getchar(); \
                         if ((ch == EOF) || (ch =='\n')) break; }

 
-- 

Eddie Wyatt 				e-mail: edw@ius1.cs.cmu.edu

rsalz@bbn.com (Rich Salz) (02/18/88)

=>>#define               clearline()             while (getchar() != '\n')
=> This is seriously bad code.  What if stdin reaches end of file?
=
=   It loops forever -- oops.  Change that to 
=#define clearline() while (1) {int ch = getchar(); \
=                         if ((ch == EOF) || (ch =='\n')) break; }

Not quite yet; the following "obvious" fragment won't compile
(try it before posting "why" to the net):
	if (a)
	    if (b)
		clearline();
	    else
		printf("Don't know about b, but a is zero.\n");

This should work:
#define clearline() \
	while (getchar() != '\n' && !feof(stdin) && !ferror(stdin))

As a general rule, you probably don't want to use { } in #define's
as  { }; is not the same as { }.
	/r$
-- 
For comp.sources.unix stuff, mail to sources@uunet.uu.net.

mlandau@bbn.com (Matt Landau) (02/18/88)

In comp.lang.c (<413@fig.bbn.com>), rsalz@bbn.com (Rich Salz) writes:
>
>As a general rule, you probably don't want to use { } in #define's
>as  { }; is not the same as { }.

One trick that works really nicely is:

	#define COMPLEX_MACRO()	    do {statement-group} while (0)

Since "do {} while (0)" is a single statement, you can nest this
inside if's without worrying about getting the nesting wrong, missing
or extra semicolons (you just always follow the invokation with one,
just as though it were a function call), etc.  

It's guaranteed that the statement-group will be executed exactly once, 
and any compiler worth its salt will figure out that it can eliminate 
the test and generate the equivalent of inline code.

Of course, lint complains bitterly, but you can't have everything.
--
 Matt Landau			Waiting for a flash of enlightenment
 mlandau@bbn.com			  in all this blood and thunder

dhesi@bsu-cs.UUCP (Rahul Dhesi) (02/18/88)

In article <413@fig.bbn.com> rsalz@bbn.com (Rich Salz) writes:
>As a general rule, you probably don't want to use { } in #define's
>as  { }; is not the same as { }.

Thomas Plum says this should work:

#define stuff(x)         do { ... } while (0)
-- 
Rahul Dhesi         UUCP:  <backbones>!{iuvax,pur-ee,uunet}!bsu-cs!dhesi

tim@ism780c.UUCP (Tim Smith, Knowledgian) (02/20/88)

Another thing that might be a good idea is to change

	if ( isupper(ch) )
		tolower(ch);

to something like

	if ( isupper(ch) )
		ch = tolower(ch);
-- 
Tim Smith					tim@ism780c.isc.com
"What's my sex, what's my name, all in all it's all the same,
 everybody plays a different game - that is all" -- Cat Stevens