C
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Functions
-
Section 4: Arrays and Strings
-
Section 5: Pointers
-
Section 6: Memory Management
-
Section 7: Structures and Unions
-
Section 8: The Preprocessor and Build Process
-
Section 9: Standard Library: stdio.h
-
Section 10: Standard Library: stdlib.h
-
Section 11: Standard Library: string.h
-
Section 12: Standard Library: ctype.h and wctype.h
-
Section 13: Standard Library: math.h, complex.h, fenv.h, tgmath.h
-
Section 14: Standard Library: Type and Limit Headers
-
Section 15: Standard Library: Error Handling and Debugging
-
Section 16: Standard Library: Localization and Encoding
-
Section 17: Standard Library: time.h
-
Section 18: Standard Library: Concurrency (C11)
-
Section 19: POSIX and System Programming (unistd.h)
-
Section 20: More Data Structures
-
Section 21: Algorithms in C
-
Section 22: Bitwise Operations
-
Section 23: Command-Line Programs
-
Section 24: Debugging and Best Practices
-
Section 25: Compiler and Language Internals
-
Section 26: Embedded and Cross-Platform Considerations
-
Section 27: Networking Basics
-
Section 28: Practical Projects
-
Section 29: Interview Practice
-
Section 30: C23 Modern Features
-
Section 31: More Practice and Review
86: Temporary Files with tmpfile
A few years ago, I was reviewing code for a colleague who was implementing a basic merge-sort for a dataset that was far too large to fit into RAM. He had taken the intuitive route: he used fopen("temp_sort.dat", "w+b") to create a scratchpad file on disk. It worked perfectly during his solo tests. But the moment we deployed it to a production server where multiple users could trigger the process simultaneously, everything fell apart. Three different processes were all trying to read and write to the exact same temp_sort.dat file at the same time. The result was a chaotic mess of interleaved data and corrupted outputs.
That's the danger of hard-coding temporary filenames. You aren't just risking collisions between concurrent processes; you're also leaving "ghost files" behind whenever your program crashes before it hits the remove() call. This is why you should reach for tmpfile() instead.
The Vanishing Act of tmpfile
The tmpfile() function is a specialized tool in <stdio.h> that handles the messy parts of temporary storage for you. When you call it, the operating system creates a unique file in a temporary directory and returns a FILE * pointer to it. The beauty of this function is its lifecycle: the file is automatically deleted as soon as you call fclose() or when your program terminates normally.
I like to think of it as a "disposable" file. You don't have to worry about what to name it, where to put it, or whether you remembered to clean up after a segmentation fault. The OS handles the naming collision problem by ensuring every call to tmpfile() gets a distinct, unique identity.
#include <stdio.h>
int main() {
FILE *temp = tmpfile();
if (temp == NULL) {
perror("Failed to create temp file");
return 1;
}
fprintf(temp, "This data is transient.\n");
// The file exists on disk right now, but you won't
// easily find it in your folder.
fclose(temp);
// The moment this is called, the file is wiped from existence.
return 0;
}
Navigating the Binary Stream
One thing that often trips people up is that tmpfile() opens the file in wb+ mode. That means it's a binary file that allows both reading and writing. Because it's a single stream, you have to be mindful of the file position pointer. If you write a hundred bytes to the file and then immediately try to read from it, you'll get nothing—because the pointer is currently sitting at the end of the data you just wrote.
Whenever you switch from writing your temporary data to reading it back, you must reset the pointer. I usually use rewind(temp) for this; it's cleaner and more explicit than calling fseek(temp, 0, SEEK_SET). Just remember: write, rewind, then read.
#include <stdio.h>
#include <string.h>
void process_large_buffer(const char *data) {
FILE *temp = tmpfile();
if (!temp) return;
// Write data to the temporary scratchpad
fwrite(data, sizeof(char), strlen(data), temp);
// We are now at the end of the file.
// To read it back, we have to go back to the start.
rewind(temp);
char buffer[100];
if (fgets(buffer, 100, temp)) {
printf("Read from temp: %s", buffer);
}
fclose(temp);
}
📋 Practical Task
Exercise: Building a Temporary Log-Reversal Tool
Imagine you are building a tool that processes a stream of log entries, but you need to output them in reverse order. Since the stream is too large to store in an array, you'll use a temporary file to store the logs first.
Your Task: Write a program that does the following:
- Prompts the user to enter several lines of text (until the user types "END").
- Uses
tmpfile()to store each line as it is entered. - Once "END" is typed, the program should not simply read the file from the start, but instead use
fseek()to read the file backwards character by character (or line by line), printing the content in reverse order to the console. - Ensure the temporary file is closed properly, triggering its automatic deletion.
There are no comments for now.