In C, many standard library functions (especially those dealing with file I/O, memory allocation, and system calls) do not throw exceptions. Instead, they return special values (like NULL, -1, or EOF) to indicate failure, and rely on a global mechanism to report why the failure occurred.
1. The Global Error Variable (errno)
The C standard library (<errno.h>) defines a global variable named errno.
- Definition:
errnois an integer variable that is set by various library functions when an error occurs during a system call or file operation. - Purpose: It holds an error code, which is a small positive integer corresponding to a specific type of error (e.g., “File not found,” “Permission denied”).
- Crucial Rule: You must check the return value of the function immediately after a failure and check
errnoright away, as subsequent function calls might overwrite its value.
To use errno, you must include:
#include <errno.h>
2. Error Reporting (perror and strerror)
Raw integer error codes are not human-readable. C provides two ways to translate the errno code into a descriptive string:
A. perror()
The perror() function is the simplest way to report a system error. It prints a user-supplied string, followed by a colon, a space, and then the human-readable description of the current errno value, followed by a newline.
Syntax: void perror(const char *s);
#include <stdio.h>
#include <errno.h>
// Example: Attempting to open a non-existent file
FILE *fp = fopen("non_existent_file.txt", "r");
if (fp == NULL) {
// The library function fopen() set errno when it failed.
perror("Error opening file");
// If errno was 2 (ENOENT - No such file or directory), the output is:
// Error opening file: No such file or directory
}
B. strerror()
The strerror() function is used if you need to access the error message string without printing it directly. It takes an integer error code (like errno) and returns a pointer to the corresponding error message string.
Syntax: char *strerror(int errnum);
#include <string.h>
#include <errno.h>
// ... after a function fails and sets errno ...
char *error_message = strerror(errno);
printf("Failure Code: %d, Message: %s\n", errno, error_message);
3. Example: Handling malloc Failure
When malloc fails to find enough memory, it returns NULL and sets errno.
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int *ptr = (int *)malloc(10000000 * sizeof(int)); // Requesting a large block
if (ptr == NULL) {
// malloc failed. Check errno (likely ENOMEM - Cannot allocate memory)
fprintf(stderr, "Fatal Error: "); // Print error message to stderr (standard error stream)
perror("Memory allocation failed");
exit(EXIT_FAILURE); // Exit with a non-zero status
}
Best Practice: When reporting errors, always write the output to the standard error stream (
stderr) instead ofstdout(standard output) usingfprintf(stderr, ...)orperror(). This ensures the error message is visible even if standard output is redirected to a file.
