CI/O Buffering

I/O Buffering

When you call printf, the text doesn't necessarily appear on the screen the instant the function returns. The standard I/O library (stdio) typically collects output in an internal memory buffer first, and only actually sends it to the terminal, file, or pipe once that buffer fills up, gets explicitly flushed, or the program exits normally. This is buffering, and it exists purely for performance — writing data in larger chunks is far cheaper than performing a system call for every single character.

The three buffering modes

Mode

When output is flushed

Typical default for

Unbuffered

Immediately, after every write

stderr (so error messages always appear right away)

Line-buffered

Whenever a newline \n is written

A terminal (interactive stdout)

Fully buffered

Only when the buffer fills up, or on an explicit flush

A regular file or a pipe (non-interactive stdout)

Notice that stdout's behavior actually depends on where its output is going — the exact same printf calls can behave differently depending on whether you run the program directly in a terminal (line-buffered) or redirect its output to a file, like ./program > output.txt (fully buffered).

Forcing output with fflush

fflush(stream) forces any buffered data for that stream to be written out immediately. This matters most when you're about to do something slow (waiting for user input, sleeping, or performing a blocking operation) right after a printf that hasn't hit a newline yet:

C
#include <stdio.h>

int main(void) {
    printf("Processing"); /* no trailing newline -- may sit in the buffer */
    fflush(stdout);        /* force it to appear right now */

    for (int i = 0; i < 3; i++) {
        /* imagine some slow work happening here */
        printf(".");
        fflush(stdout);
    }
    printf(" done!\n");
    return 0;
}

Without the fflush calls, a fully buffered stdout (for example, when the program's output is redirected to a file) might not show anything at all until the whole loop finishes and the buffer is flushed as a block.

Why mixing printf with lower-level writes can reorder output

printf writes go through stdio's buffer, but a lower-level call like POSIX write() bypasses that buffer entirely and sends bytes straight to the operating system. If you mix the two on the same file descriptor, the write() output can show up before buffered printf output that was actually issued first, simply because the printf data was still sitting in the buffer when write() fired:

C
#include <stdio.h>
#include <unistd.h>

int main(void) {
    printf("A: from printf (buffered)");   /* no newline yet -- may be held back */
    write(1, "B: from write (unbuffered)\n", 27); /* goes out immediately */
    printf("\n");
    return 0;
}
/* Depending on buffering, "B" can appear on screen before "A",
   even though the printf("A: ...") call happened first in the source. */
Don't mix stdio and raw system calls without flushing
If you must mix `printf`/`fputs`-style calls with lower-level I/O (`write`, `read`) on the same stream, call `fflush` on the `stdio` side first, so the buffered data is sent out before the raw call executes. Otherwise, the visible order of output can differ from the order your code issued it in.
Buffering is about output timing, not correctness
Buffering never loses data under normal program termination — `stdio` automatically flushes all open streams when a program exits normally (via `return` from `main` or a normal call to `exit`). The concern is purely about *when* output becomes visible, which matters for interactive prompts, progress indicators, and debugging output right before a crash (a program that terminates abnormally, e.g. via a segfault, may lose unflushed buffered output).