I was testing this code from the GNU libc manual:
/* Use this variable to remember original terminal attributes. */
struct termios saved_attributes;
tcsetattr (STDIN_FILENO, TCSANOW, &saved_attributes);
struct termios tattr;
/* Make sure stdin is a terminal. */
if (!isatty (STDIN_FILENO))
fprintf (stderr, "Not a terminal.\n");
/* Save the terminal attributes so we can restore them later. */
tcgetattr (STDIN_FILENO, &saved_attributes);
/* Set the funny terminal modes. */
tcgetattr (STDIN_FILENO, &tattr);
tattr.c_lflag &= ~(ICANON|ECHO); /* Clear ICANON and ECHO. */
tattr.c_cc[VMIN] = 1;
tattr.c_cc[VTIME] = 0;
tcsetattr (STDIN_FILENO, TCSAFLUSH, &tattr);
read (STDIN_FILENO, &c, 1);
if (c == '\004') /* C-d */
write(STDOUT_FILENO, &c, sizeof(char))
You are being trumped by user buffering!
putchar(3) is part of libc I/O API, while
write(2) is a system call -- well, not quite a system call, but for simplicity's sake, let's consider it is for now.
There are three types of buffering in libc: unbuffered, block buffered, and line buffered. If a stream is unbuffered, data goes to the underlying file (or terminal) as soon as it is written; if it's block buffered, data is saved in the memory block until it fills up and then it's written all at once; however, if it's line buffered, data is transmitted to the file (or terminal) when a newline character is found.
If a stream is connected to a terminal, as normally is the case of standard output, it's line buffered. So, this is your case: when you press enter, the newline character
\n causes the (line) buffer to be written to standard output. However, when you call
write(2), libc user buffering is bypassed and data is written to the corresponding file descriptor (STDOUT_FILENO).
So, as I said earlier,
write(2) is a system call; but in truth, when you call
write, you are calling a library wrapper to the system call, which handles the strict protocol the system call follows (e.g., where it expects arguments, etc).
By the way, everything I said here can be found in the man pages for
setbuf(3). The numbers in parentheses refer to the section in the manual:
2 is for system calls,
3 is for library functions (
man man should give you a list of sections and their topic).
Hope it helps.