#1
  1. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2001
    Posts
    149
    Rep Power
    14

    Reading only one character from stdin.


    I'm coming off a 2-3 year hiatus from programming in C and trying to re-learn the language. Unfortunately, I have source from before, but no notes to learn from.

    I'm having a problem with reading in a single character using scanf. I've also tried using getc. Basically, I have a little program like this one below:
    Code:
    int main(void)
    {
      char myChar;
      unsigned char flag = 0;
    
      while (flag == 0)
      {
        printf("Enter character: ");
        scanf("%c",&myChar);
    
        printf("You entered '%c'.\n\n",myChar);
    
        if (myChar == 'q')
          flag = 1;
      }
    
      return (0);
    }
    Now, I have two problems with this code:
    1) When you enter a single character, since the newline character is still in the input stream, the next time the loop comes around, '\n' is passed to scanf, which produces this result:
    Code:
    Enter Character: J
    You entered 'J'
    
    Enter Character: You entered '
    '
    
    Enter Character:
    ... not what I want. So how do I handle the newline character in this situation? I've tried this with getc as well and have the same results.

    2) Besides the newline character, if the user enters more than one letter at the prompt, all the letters get processed through the loop. So you get something like:
    Code:
    Enter Character: hello
    You entered 'h'
    
    Enter Character: You entered 'e'
    
    Enter Character: You entered 'l'
    
    Enter Character: You entered 'l'
    
    Enter Character: You entered 'o'
    
    Enter Character: You entered '
    '
    
    Enter Character:
    So I assume the two problems are related somehow, but I'm completely stumped as to how to resolve the problem. Looking back through my old source code I see things like:
    Code:
    myChar = getc(stdin);
    fflush(stdin);
    ... which apparently worked (again, it was a while back, I can't remember for sure). But when I compile the same code on my system now, it fails. Doesn't make sense since I thought fflush was only for output buffers and not input ones.

    Can anyone help me out understanding all this again? Anyone know of any good online 'C refreshers' I can visit?

    Thanks,

    - coredumped.
  2. #2
  3. jasondoucette.com
    Devshed Newbie (0 - 499 posts)

    Join Date
    Feb 2003
    Location
    Canada
    Posts
    378
    Rep Power
    12
    Try _getch()

    I guess the reason the two functions you tried do not work is because they do not return control to the program after a character is entered (i.e. they wait for a CR - and thus, the CR is also placed into stdin). _getch() does not do this. Try this code for example:

    Code:
    char ch;
    while (true)
    {
    	ch = _getch();
    	if ((ch == '1') || (ch == '2') || (ch == '3') break;
    } 
    printf("%c\n\n",ch);
    It will accept only the keys 1, 2, or 3 as input to break the loop. All other keys are ignored. And, the key is NOT printed to the screen automatically - it is done with the printf() call. I think this is sufficient for what you are looking for.
  4. #3
  5. No Profile Picture
    Junior Member
    Devshed Newbie (0 - 499 posts)

    Join Date
    May 2003
    Posts
    16
    Rep Power
    0
    Try setting the terminal to non-canonical mode using the ioctl() system call (it'll read only one char at a time - I think it only works on UNIXes):

    http://www.unidata.ucar.edu/cgi-bin/man-cgi?termio+7

    An (incomplete) example:

    main(){

    struct termios oldT, newT;
    char c;

    ioctl(0,TCGETS,&oldT); /*get current mode

    newT=oldT;
    newT.c_lflag &= ~ECHO; /* echo off */
    newT.c_lflag &= ~ICANON; /*one char @ a time*/

    ioctl(0,TCSETS,&newT); /* set new terminal mode */

    read(0,&c,1); /*read 1 char @ a time from stdin*/

    ioctl(0,TCSETS,&oldT); /* restore previous terminal mode */

    }

    You may need to set two more flags to enable true non-canonical input, keep posting :)

IMN logo majestic logo threadwatch logo seochat tools logo