12

My main intention was to make getchar return as soon as it gets a character instead of waiting for the ENTER key. I tried this

int main()
{
    setvbuf(stdin,NULL,_IONBF,0);
    getchar();

    return 0;
}

Comparing this with the prototype of setvbuf

setvbuf ( FILE * stream, char * buffer, int mode, size_t size );

it should set stdin to unbuffered mode.

But still getchar() keeps waiting for ENTER

I've seen related posts like this

Printing while reading characters in C

which are suggesting alternate methods to make stdin unbuffered. But I am curious to know as to why setvbuf method does not work

Community
  • 1
  • 1
Pavan Manjunath
  • 27,404
  • 12
  • 99
  • 125
  • You must call `setvbuf()` before any "movement" on the stream ... so first thing in `main()`. – pmg Apr 20 '12 at 14:03
  • @pmg I updated my post to reflect what I tried. But still it doesn't work – Pavan Manjunath Apr 20 '12 at 14:12
  • I think the problem is not with `setvbuf()`. I tried your program with and without `setvbuf()` and the behaviour is different. Without `setvbuf()` all characters up to and including the ENTER are consumed (even though it is consumed only after typing ENTER); with `setvbuf()` only the first character is consumed, the remaining characters are used as a following bash command. – pmg Apr 20 '12 at 14:23

2 Answers2

21

The terminal driver doesn't return anything until you hit return, even if the read() operation would accept what's already there.

To get character-by-character input from a terminal, you have to get it out of canonical mode into raw or cbreak mode, and that requires different operations altogether. Take a look at the POSIX manual on 'General Terminal Interface' for how to control the terminal. Or consider using the curses library.

See also: Canonical vs non-canonical terminal input

Community
  • 1
  • 1
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • `setvbuf(stdin,NULL,_IONBF,0);` is supposed to do that right? I mean `setvbuf` works fine for all file pointers but not for `stdin`? – Pavan Manjunath Apr 20 '12 at 14:19
  • 7
    No. `setvbuf()` just tells the standard I/O library in your program to use no buffer; it doesn't tell the terminal driver anything. – Jonathan Leffler Apr 20 '12 at 14:21
1

In case you are trying this under Linux or another Unix-like system, it is the terminal that buffers the input and only passes an entire line. You can use ncurses to circumvent this:

#include <ncurses.h>

int main()
{
    initscr();
    getch();
    endwin();

    return 0;
}

Compile with:

gcc -o main main.c -lncurses
user1202136
  • 11,171
  • 4
  • 41
  • 62