C Error Handling
Managing and responding to runtime errors effectively
⚠️ What is Error Handling?
Error handling in C involves detecting, managing, and responding to runtime errors gracefully. It prevents program crashes and provides meaningful feedback to users when unexpected situations occur.
#include <stdio.h>
#include <errno.h>
int main() {
FILE *file = fopen("nonexistent.txt", "r");
if (file == NULL) {
printf("Error: %s\n", strerror(errno));
return 1;
}
return 0;
}
Output:
Error: No such file or directory
Key Error Handling Concepts
Return Values
Check function return values for errors
if (result == -1) {
// Handle error
}
errno Variable
Global variable storing error codes
if (errno != 0) {
perror("Error");
}
Defensive Programming
Validate inputs and check conditions
if (ptr == NULL) {
return -1;
}
Error Recovery
Attempt to recover from errors
if (malloc_failed) {
free_resources();
}
🔹 File Operation Error Handling
Proper error handling is essential when performing file operations in C programs. File operations can fail for numerous reasons including missing files, insufficient permissions, or disk space issues. Always check if file operations succeed by verifying return values and file pointers. Use fopen() to verify the file opened successfully before attempting to read or write, check fclose() return values to ensure file closure was successful, and implement appropriate error messages to help users understand what went wrong during file operations.
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *file = fopen("data.txt", "r");
if (file == NULL) {
fprintf(stderr, "Error: Cannot open file\n");
return EXIT_FAILURE;
}
// File operations here
printf("File opened successfully\n");
fclose(file);
return EXIT_SUCCESS;
}
Output (if file doesn't exist):
Error: Cannot open file
🔹 Memory Allocation Error Handling
Dynamic memory allocation requires careful error checking to prevent memory-related crashes and undefined behavior. When using malloc() or calloc(), always verify that memory allocation succeeded before attempting to use the allocated memory. Check if the returned pointer is NULL, which indicates allocation failure. Never assume memory allocation will always succeed, as it can fail when the system runs out of available memory. Implement proper error handling with informative messages, and always free allocated memory when it's no longer needed to prevent memory leaks.
#include <stdio.h>
#include <stdlib.h>
int main() {
int *arr = malloc(1000 * sizeof(int));
if (arr == NULL) {
fprintf(stderr, "Error: Memory allocation failed\n");
return EXIT_FAILURE;
}
printf("Memory allocated successfully\n");
// Use the array
arr[0] = 42;
printf("First element: %d\n", arr[0]);
free(arr);
return EXIT_SUCCESS;
}
Output:
Memory allocated successfully
First element: 42
🔹 Using perror() and strerror()
The perror() and strerror() functions provide descriptive error messages that significantly aid in debugging. When system calls fail, these functions translate error codes into human-readable messages explaining what went wrong. perror() automatically prints the error message preceded by your custom text, while strerror() returns the error message string for custom formatting. Using these functions makes debugging easier by providing clear information about why operations failed, helping you understand issues without manually checking error codes.
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main() {
FILE *file = fopen("missing.txt", "r");
if (file == NULL) {
// Method 1: Using perror()
perror("File error");
// Method 2: Using strerror()
printf("Error details: %s\n", strerror(errno));
return 1;
}
fclose(file);
return 0;
}
Output:
File error: No such file or directory
Error details: No such file or directory