COpening & Closing Files

Opening & Closing Files

fopen() is the entry point for all file I/O in C. It attempts to open the file at the given path in the given mode, and hands you back a FILE * handle to use for every subsequent operation.

fopen() and Mode Strings

C
FILE *fopen(const char *filename, const char *mode);

Mode

Meaning

"r"

Open an existing text file for reading. Fails if the file does not exist.

"w"

Open a text file for writing. Creates it if missing, truncates it to zero length if it exists.

"a"

Open a text file for appending. Creates it if missing; writes always go to the end.

"r+"

Open an existing text file for both reading and writing. Fails if it does not exist.

"w+"

Open a text file for reading and writing, truncating it if it exists, creating it otherwise.

"rb", "wb", "ab", "rb+", ...

Same as above, but in binary mode (add b) — see the Binary Files page.

Always Check for NULL

fopen() returns NULL if the file could not be opened for any reason — it does not exist, permissions deny access, too many files are already open, the disk is unavailable, and so on. That return value must be checked before the handle is used for anything.

Dereferencing a NULL FILE* crashes the program

C
#include <stdio.h>

int main(void)
{
    FILE *fp = fopen("does_not_exist.txt", "r");

    /* BUG: fp is NULL here because the file doesn't exist,
       but we use it anyway. */
    fputs("hello\n", fp);   /* undefined behavior -- typically crashes */

    return 0;
}
Every use of `fp` after a failed `fopen()` is undefined behavior. On most systems this crashes with a segmentation fault, but it is not guaranteed to fail loudly or immediately — always check first.

C
#include <stdio.h>

int main(void)
{
    FILE *fp = fopen("does_not_exist.txt", "r");

    if (fp == NULL) {
        printf("Could not open file for reading.\n");
        return 1;   /* bail out cleanly instead of crashing */
    }

    /* fp is guaranteed non-NULL from this point on */
    fclose(fp);
    return 0;
}
Closing With fclose()

fclose(fp) releases the operating system resources tied up by the open file and — critically for writes — flushes any data still sitting in the library's internal output buffer out to disk. fclose() returns 0 on success and EOF on failure, which is also worth checking for write-heavy code.

C
#include <stdio.h>

int main(void)
{
    FILE *fp = fopen("output.txt", "w");
    if (fp == NULL) {
        return 1;
    }

    fputs("important data\n", fp);

    if (fclose(fp) != 0) {
        printf("Warning: error while closing the file.\n");
    }

    return 0;
}
Forgetting to close a file
Skipping `fclose()` leaks a file handle for as long as the process runs — most operating systems cap the number of files a process can have open at once, so leaking enough handles causes later `fopen()` calls to fail. Worse, buffered writes that have not been flushed yet can simply be lost if the program exits without closing the file, leaving the file on disk incomplete or empty even though your code called `fputs`/`fprintf` successfully.
  • Always pair a successful fopen() with exactly one fclose()

  • On every early-return / error path after opening a file, make sure it still gets closed

  • The operating system will close any files still open when the process exits, but relying on that instead of an explicit fclose() is fragile and considered bad practice

Note
The C standard library also provides `fflush(fp)` to force buffered output to be written out without closing the file — handy for long-running programs that write incrementally and want data durable on disk before the file is eventually closed.