Frontend Labs
⋯

12. File I/O: buffering, binary vs. text mode, errno

12.1 stdio buffering — why your output sometimes "doesn't show up"

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

int main(void) {
    printf("about to crash...");   // stdout is line-buffered (tty) or fully buffered (pipe/file) —
                                    // this may sit in a buffer, unflushed, if stdout isn't a tty
    fflush(stdout);                 // force it out now
    // *(int *)0 = 1;               // simulate a crash — without the fflush above,
                                     // the message might never appear
    return 0;
}

stderr is unbuffered by default specifically so error messages appear immediately even if the process crashes right after — this is why diagnostics go to stderr, not stdout.

12.2 Reading a whole file, correctly

#include <stdio.h>
#include <stdlib.h>

char *read_whole_file(const char *path, size_t *out_len) {
    FILE *f = fopen(path, "rb");            // "b" matters: on Windows, text mode translates
    if (!f) return NULL;                    // \r\n <-> \n, corrupting binary data

    fseek(f, 0, SEEK_END);
    long size = ftell(f);
    if (size < 0) { fclose(f); return NULL; }
    rewind(f);

    char *buf = malloc((size_t)size + 1);
    if (!buf) { fclose(f); return NULL; }

    size_t read = fread(buf, 1, (size_t)size, f);
    fclose(f);

    if (read != (size_t)size) { free(buf); return NULL; }
    buf[size] = '\0';
    if (out_len) *out_len = read;
    return buf;    // caller owns this — must free()
}

12.3 errno: check it right after the call that can fail, nothing else

#include <errno.h>
#include <stdio.h>
#include <string.h>

int main(void) {
    FILE *f = fopen("/does/not/exist", "r");
    if (!f) {
        // errno is set by the failing call; a call in between (even printf) can clobber it
        fprintf(stderr, "fopen failed: %s\n", strerror(errno));
        return 1;
    }
    fclose(f);
    return 0;
}

perror("fopen") is the shorthand for the same thing: perror prints "fopen: No such file or directory\n" using the current errno automatically.


Generated from real-life-c-guide.md · 8 Oct 2026 16:36