views:

1735

answers:

5

If I want to receive a one character input in C, how would I check to see if extra characters were sent, and if so, how would I clear that?

Is there a function which acts like getc(stdin), but which doesn't prompt the user to enter a character, so I can just put while(getc(stdin)!=EOF);? Or a function to peek at the next character in the buffer, and if it doesn't return NULL (or whatever would be there), I could call a(nother) function which flushes stdin?

Edit

So right now, scanf seems to be doing the trick but is there a way to get it to read the whole string, up until the newline? Rather than to the nearest whitespace? I know I can just put "%s %s %s" or whatever into the format string but can I handle an arbitrary number of spaces?

A: 

Use a read that will take a lot of characters (more than 1, maybe 256), and see how many are actually returned. If you get more than one, you know; if you only get one, that's all there were available.

You don't mention platform, and this gets quite tricky quite rapidly. For example, on Unix (Linux), the normal mechanism will return a line of data - probably the one character you were after and a newline. Or maybe you persuade your user to type ^D (default) to send the preceding character. Or maybe you use control functions to put the terminal into raw mode (like programs such as vi and emacs do).

On Windows, I'm not so sure -- I think there is a getch() function that does what you need.

Jonathan Leffler
+3  A: 

You cannot flush the input stream. You will be invoking undefined behavior if you do. Your best bet is to do:

int main() {
  int c = getchar();
  while (getchar() != EOF);
  return 0;
}

To use scanf magic:

#include <stdio.h>
#include <stdlib.h> 

#define str(s) #s
#define xstr(s) str(s)
#define BUFSZ 256

int main() {
  char buf[ BUFSZ + 1 ];
  int rc = scanf("%" xstr(BUFSZ) "[^\n]%*[^\n]", buf);
  if (!feof(stdin)) {
    getchar();
  }
  while (rc == 1) {
    printf("Your string is: %s\n", array);
    fflush(stdout);
    rc = scanf("%" xstr(LENGTH) "[^\n]%*[^\n]", array);
    if (!feof(stdin)) {
        getchar();
    }
   }
   return 0;
}
dirkgently
I tried, but every time the while loop calls getchar(), it prompts for another character... doesn't it? It seems to.
Carson Myers
The while loop waits for another character. Depending on your system, there will be a keystroke combination to signal the end of input. That should do the trick.
dirkgently
so getchar() will only ask the user for input, if the input buffer is empty? And, while asking the user, if the user enters more than one character, that fills up the input buffer?
Carson Myers
Any method you use for reading in a character is susceptible to these problems. What are you trying to achieve?
dirkgently
I wasn't really pointing out a problem, I am just unclear as to the behaviour of each function... what's the difference between getc() and getchar(), besides the argument for a filestream? I would use getch (or look into it) but that's not standard... right now I'm playing with scanf, but does scanf leave the buffer empty?
Carson Myers
major difference: getc and friends do unformatted input, scanf does formatted input. There are then more arcane differences: getc (and putc) may be implemented as macros. However, unlike other macros which are required to evaluate their arguments only once, these (getc and putc) can evaluate their FILE* arguments more than once. Hence the provision for fgetc (and fputc). There ought not be any semantic differences though for most programs.
dirkgently
Remember that terminals tend to be line-buffered, meaning your program will (usually) not get any input until the user hits enter.On Windows, I believe there's a Win32 API call to turn off that buffering (but I can't be sure - it's been over 8 years since I last looked at it). On Linux, I believe (I've never actually don it myself) that <a href="http://www.flipcode.com/archives/_kbhit_for_Linux.shtml">termios</a> should do the trick.
Vitali
A: 

Why don't you use scanf instead of getc, by using scanf u can get the whole string.

uzurpatorul
is scanf good? I mean, I've read (I forget where) that it's really easy to run into problems with it
Carson Myers
you can have buffer-overflow problems, however there are scanf variants in windows scanf_s (_s stands for secure) that protects you from that.
uzurpatorul
A: 

You can use getline to read a whole line of input.

Alternatively (in response to your original question), you can call select or poll on stdin to see if there are additional characters to be read.

btmorex
select or poll? Is getline even in C? I thought it was just a member of cin in C++...
Carson Myers
getline is in glibc, but it's not standard C. I guess you can't use it if you're on windows. At least, select should be available everywhere though.
btmorex
A: 

I had a similar problem today, and I found a way that seems to work. I don't know the details of your situation, so I don't know if it will work for you or not.

I'm writing a routine that needs to get a single character from the keyboard, and it needs to be one of three specific keystrokes (a '1', a '2', or a '3'). If it's not one of those, the program needs to send and error message and loop back for another try.

The problem is that in addition to the character I enter being returned by getchar(), the 'Enter' keystroke (which sends the keystroke to the program) is saved in an input buffer. That (non-printing) newline-character is then returned by the getchar() facility in the error-correction loop, resulting further in a second error message (since the newline-character is not either a '1', a '2', nor a '3'.)

The issue is further complicated because I sometimes get ahead of myself and instead of entering a single character, I'll enter the filename that one of these options will request. Then I have a whole string of unwanted characters in the buffer, resulting in a long list of error messages scrolling down the screen.

Not cool.

What seems to have fixed it, though, is the following:
c = getchar();
while(getchar() != '\n') ;

The first line is the one that actually uses the character I enter. The second line disposes of whatever residue remains in the input buffer. It simply creates a loop that pulls a character at a time from the input buffer. There's no action specified to take place while the statement is looping. It simply reads a character and, if it's not a newline, goes back for the next. When it finds a newline, the loop ends and it goes on to the next order of business in the program.