I wrote the following program.
void main()
{
int *piarrNumber1 = (int *) calloc(1, sizeof(int));
int iUserInput = 0;
scanf(\"%d\", &iUse
Details are operating system specific (since standard C99 does not know about terminals).
I assume you are using Linux.
First, stdio(3) is buffering the standard input stream and most other FILE*
streams. You might try to change that with setvbuf(3), but this affects output buffering only.
More importantly, when stdin (actually the file descriptor used by it, i.e. STDIN_FILENO
which is generally the value of fileno(stdin)
) is a terminal (see isatty(3) to test that), the linux kernel is usually line-buffering the terminal (so called cooked mode) - at least to handle the backspace key. You might change that by switching the tty to raw mode (as every editor like emacs
or vim
or nano
would do). See this question. But you should reset the cooked mode before your program exits.
So in normal cases, two levels of buffering happen: in the kernel for the line discipline of the terminal, and in the libc
for the buffering of stdin
Read the tty demystified page and the Text Terminal HowTo
In practice, if you want sophisticated terminal input, use some library like ncurses or readline (don't bother using just termios)
See also stty(1) & termios(3) & tty_ioctl(4); read about ANSI escape codes.
Notice that this line buferring at two levels (libc
and kernel) is specific to ttys. When stdin
is a pipe(7) (as in echo foo | yourprogram
) or a file (as in yourprogram < yourinputfile.txt
) things are different.
In short, ttys are hard to understand, because they mimic complex and arcane hardware devices of the 1950s-1970s era.
Most OSes buffer keyboard input so that they can process backspaces properly -- the OS keeps input in a buffer and only gives it to the program when Enter is hit.
Most OSes also provide ways to control this, but the way is different for different OSes. On POSIX systems, the tcsetattr
command is used to control this terminal buffering, along with lots of other things. You can read the termios(3) manual page for lots of information about it. You get the behavior you want by setting non-canonical mode:
#include <termios.h>
#include <unistd.h>
:
struct termios attr;
tcgetattr(0, &attr);
attr.c_lflag &= ~ICANON;
tcsetattr(0, TCSANOW, &attr);
which causes the OS to send every keystroke to your program immediately (except for a few special ones it intercepts, like ctrl-C), without waiting for Enter, and without processing backspaces either.
Note that terminal settings are persistent across programs that use the same terminal, so you probably want to save the original settings as of when your program started and restore them before it exits.