C clearerr function
last modified April 6, 2025
Error handling is crucial in C file operations to ensure robust and reliable
programs. The clearerr function helps manage file stream error
indicators effectively. This tutorial explores clearerr in depth,
explaining its purpose, behavior, and practical applications. You'll learn how
to reset error and EOF flags to continue file operations after encountering
issues. Mastering clearerr enhances your ability to handle file I/O
errors gracefully.
What Is clearerr?
The clearerr function clears the error and end-of-file (EOF)
indicators for a file stream. It takes a single parameter: a pointer to the
FILE object. When called, it resets both the error and EOF flags,
allowing subsequent operations to proceed. This function is particularly useful
after encountering an error when you want to retry operations. Note that
clearerr doesn't fix the underlying issue causing the error.
Basic Syntax
The function declaration for clearerr is straightforward:
void clearerr(FILE *stream);
The function doesn't return any value and simply clears the error state of the
specified stream. The stream parameter must point to a valid,
opened file stream. After calling clearerr, you can check the
stream's status again using feof or ferror.
Clearing EOF Indicator
This example demonstrates how to use clearerr to reset the EOF flag.
#include <stdio.h>
int main() {
FILE *fp = fopen("test.txt", "r");
if (fp == NULL) {
perror("Failed to open file");
return 1;
}
// Read past EOF
int ch;
while ((ch = fgetc(fp)) != EOF) {
putchar(ch);
}
printf("\nEOF reached. feof(): %d\n", feof(fp));
clearerr(fp); // Clear EOF indicator
printf("After clearerr. feof(): %d\n", feof(fp));
fclose(fp);
return 0;
}
This code first reads a file until EOF is reached, which sets the EOF indicator.
The feof function confirms this by returning non-zero. After calling
clearerr, feof returns zero, showing the EOF flag was
cleared. Note that the file position remains at EOF unless moved with
fseek or rewind.
Handling Read Errors
This example shows how to clear an error condition after a failed read operation.
#include <stdio.h>
int main() {
FILE *fp = fopen("test.txt", "r");
if (fp == NULL) {
perror("Failed to open file");
return 1;
}
// Simulate error by closing the file descriptor
fclose(fp);
int ch = fgetc(fp); // This will fail
if (ferror(fp)) {
printf("Error occurred. ferror(): %d\n", ferror(fp));
clearerr(fp); // Clear the error
printf("After clearerr. ferror(): %d\n", ferror(fp));
}
return 0;
}
Here, we deliberately cause an error by trying to read from a closed file. The
ferror function detects this error condition. After calling
clearerr, ferror returns zero, indicating the error
flag was cleared. Remember that clearing the error doesn't make the stream usable
again if it was closed.
Combining with fseek
This example combines clearerr with fseek to recover
from errors.
#include <stdio.h>
int main() {
FILE *fp = fopen("data.bin", "rb+");
if (fp == NULL) {
perror("Failed to open file");
return 1;
}
// Try to read from write-only stream (simulated error)
int value;
if (fread(&value, sizeof(int), 1, fp) != 1) {
if (ferror(fp)) {
printf("Read error occurred. Clearing...\n");
clearerr(fp);
}
}
// Reset position and try writing
fseek(fp, 0, SEEK_SET);
value = 42;
if (fwrite(&value, sizeof(int), 1, fp) != 1) {
perror("Write failed");
}
fclose(fp);
return 0;
}
This code attempts to read from what might be a write-only stream (depending on
file permissions). After detecting the error with ferror, it clears
the error state with clearerr and uses fseek to reset
the file position. The subsequent write operation then proceeds normally. This
shows how to recover from certain types of errors.
Error Recovery in Loops
This example demonstrates using clearerr in a read loop for robust
error handling.
#include <stdio.h>
#include <unistd.h>
int main() {
FILE *fp = fopen("input.txt", "r");
if (fp == NULL) {
perror("Failed to open file");
return 1;
}
char buffer[256];
int attempts = 3;
while (attempts-- > 0) {
if (fgets(buffer, sizeof(buffer), fp) == NULL) {
if (feof(fp)) {
printf("End of file reached\n");
break;
} else if (ferror(fp)) {
printf("Read error (attempts left: %d)\n", attempts);
clearerr(fp);
sleep(1); // Wait before retry
continue;
}
}
printf("Read: %s", buffer);
}
fclose(fp);
return 0;
}
This code implements a retry mechanism when read errors occur. It attempts to
read lines up to three times if errors are encountered. After each error, it
uses clearerr to reset the error state before retrying. The
sleep call simulates a delay that might help in real-world
scenarios (like waiting for network resources). This pattern is useful for
handling transient errors.
Checking Error State Before Clearing
This example shows good practice by checking error state before clearing it.
#include <stdio.h>
int main() {
FILE *fp = fopen("test.txt", "r");
if (fp == NULL) {
perror("Failed to open file");
return 1;
}
// Read until EOF
while (fgetc(fp) != EOF);
printf("Before clearerr:\n");
printf("feof(): %d, ferror(): %d\n", feof(fp), ferror(fp));
clearerr(fp);
printf("After clearerr:\n");
printf("feof(): %d, ferror(): %d\n", feof(fp), ferror(fp));
fclose(fp);
return 0;
}
This code demonstrates the importance of checking error states before clearing
them. It reads a file to EOF, then shows the state of both EOF and error flags
before and after calling clearerr. This practice helps in debugging
and understanding the exact state of your file stream during operations. Always
verify the need to clear errors rather than doing it unconditionally.
Handling Temporary File Errors
This example shows handling temporary errors during file operations.
#include <stdio.h>
#include <errno.h>
int main() {
FILE *fp = fopen("tempfile.txt", "r+");
if (fp == NULL) {
perror("Failed to open file");
return 1;
}
// Simulate a temporary error (e.g., network hiccup)
errno = EIO; // Input/output error
ferror(fp); // Set the error indicator
if (ferror(fp)) {
printf("Temporary error occurred (errno: %d)\n", errno);
clearerr(fp);
errno = 0; // Also reset errno
// Try the operation again
printf("Retrying operation...\n");
if (fprintf(fp, "Retry data") < 0) {
perror("Operation failed again");
} else {
printf("Retry succeeded\n");
}
}
fclose(fp);
return 0;
}
This example simulates a temporary I/O error (like a network hiccup) by manually
setting errno. After detecting the error with ferror,
it clears both the stream error (with clearerr) and the global
errno. The operation is then retried. This pattern is useful for
handling transient errors in real-world applications where immediate retry might
succeed.
Best Practices for Using clearerr
- Check Before Clearing: Always verify error state with
ferrororfeofbefore callingclearerr. - Combine with Position Functions: Use
fseekorrewindwithclearerrwhen appropriate. - Don't Mask Persistent Errors: Ensure you're not repeatedly clearing errors that indicate serious problems.
- Document Error Handling: Comment your code to explain why and when you're clearing errors.
- Consider Alternative Approaches: Sometimes reopening the file is better than clearing errors.
Source
This tutorial has explored the clearerr function in depth, showing
how to effectively manage error states in C file operations. Proper error
handling makes your programs more robust and reliable when working with files.
Author
List C Standard Library.