Skip to Content
Course content

82: Opening and Closing Files with fopen/fclose

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I've been thinking about that little game project we discussed. Right now, every time we restart the program, the player's high score resets to zero. That's annoying. We need a way to keep that score on the disk so it persists. In C, we don't just "save a variable"; we have to interact with the file system using a file pointer.

Trying to save a high score

Let's start simple. I'll try to open a file called highscore.txt and write a number to it. I know I need fopen, which gives me a FILE * (a pointer to a file structure). I'll just toss the score in there and call it a day.

#include <stdio.h>

int main() {
    FILE *fptr;
    int score = 1500;

    fptr = fopen("highscore.txt", "w");
    fprintf(fptr, "%d", score);

    return 0;
}

I ran this, and it didn't crash. I checked the folder, and highscore.txt exists and contains "1500". Seems easy, right? But here is where we run into a problem. I tried to run it again, but I noticed something strange: if I had a bunch of other data in that file, it was completely gone. The "w" mode just wiped everything out the moment I opened it. That's a dangerous way to handle data if you aren't careful.

The "It didn't actually save" mystery

Now, let's say I change the code to write a larger amount of data—maybe a whole list of player stats. I noticed that if the program crashes or I force-quit it immediately after the fprintf, the file is sometimes empty or corrupted. Why?

It's because of buffering. C doesn't actually write to the disk the very millisecond you call fprintf; it stores the data in a temporary buffer in memory to make things faster. The data only actually hits the disk when the buffer fills up or when we explicitly tell the system we're done. That's where fclose comes in. I forgot it in my first snippet. Let's fix that.

#include <stdio.h>

int main() {
    FILE *fptr;
    int score = 1500;

    fptr = fopen("highscore.txt", "w");
    if (fptr != NULL) {
        fprintf(fptr, "%d", score);
        fclose(fptr); // This flushes the buffer and releases the file
    }

    return 0;
}

By adding fclose(fptr), I'm telling the OS, "I'm finished with this file, go ahead and commit everything to the physical drive." If you leave files open, you're leaking system resources, and you're gambling with your data.

Handling the "What if it fails?" scenario

I just tried to run this on a directory where I didn't have write permissions, and the program crashed with a segmentation fault. I looked at the code and realized I was calling fprintf on fptr even if fopen failed. If fopen can't open the file, it returns NULL. Trying to write to NULL is a great way to crash your app.

You'll see a lot of C programmers do a "NULL check" immediately after opening. It's not optional; it's a necessity. I've added that check in the snippet above, but let's look at the logic: if fptr is NULL, we shouldn't even attempt to use it.

Deciding how to open the file

Earlier, I mentioned that "w" wipes the file. I spent a few minutes experimenting with the mode strings to see what actually happens. Here is what I found:

  • "w" (Write): Creates an empty file. If the file already exists, its contents are destroyed. Use this for fresh saves.
  • "r" (Read): Opens an existing file. If the file doesn't exist, fopen returns NULL. You can't write to this.
  • "a" (Append): Opens a file and moves the cursor to the very end. If the file doesn't exist, it creates it. This is perfect for log files where you want to keep the old data and just add new entries.

Depending on whether I'm updating a high score (overwrite) or adding to a combat log (append), I'll switch between these modes. The pattern is always the same: fopen → NULL check → work → fclose.




📋 Practical Task

Exercise: Persistent Player Inventory Logger

Build a small utility that simulates saving a player's inventory to a file. Your program should do the following:

  • Create a file named inventory.txt.
  • Use the append mode ("a") so that every time you run the program, the new items are added to the list rather than replacing the old ones.
  • Ask the user to input a single item name (a string) and the quantity of that item (an integer).
  • Write that item and quantity to the file in a readable format (e.g., "Health Potion: 5").
  • Ensure you check if the file opened successfully before writing and remember to close the file properly.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.