- C Programming Tutorial
- C - Home
- Basics of C
- C - Introduction
- C - Features
- C - Basics
- C - History
- C - Structure of C Program
- C - Program Structure
- C - Hello World
- C - Compilation Process
- C - Comments
- C - Tokens
- C - Keywords
- C - Identifiers
- C - User Input
- C - Basic Syntax
- C - Data Types
- C - Variables
- C - Integer Promotions
- C - Type Conversion
- C - Type Casting
- C - Booleans
- Constants and Literals in C
- C - Constants
- C - Literals
- C - Escape sequences
- C - Format Specifiers
- Operators in C
- C - Operators
- C - Arithmetic Operators
- C - Relational Operators
- C - Logical Operators
- C - Bitwise Operators
- C - Assignment Operators
- C - Unary Operators
- C - Increment and Decrement Operators
- C - Ternary Operator
- C - sizeof Operator
- C - Operator Precedence
- C - Misc Operators
- Decision Making in C
- C - Decision Making
- C - if statement
- C - if...else statement
- C - nested if statements
- C - switch statement
- C - nested switch statements
- Loops in C
- C - Loops
- C - While loop
- C - For loop
- C - Do...while loop
- C - Nested loop
- C - Infinite loop
- C - Break Statement
- C - Continue Statement
- C - goto Statement
- Functions in C
- C - Functions
- C - Main Function
- C - Function call by Value
- C - Function call by reference
- C - Nested Functions
- C - Variadic Functions
- C - User-Defined Functions
- C - Callback Function
- C - Return Statement
- C - Recursion
- Scope Rules in C
- C - Scope Rules
- C - Static Variables
- C - Global Variables
- Arrays in C
- C - Arrays
- C - Properties of Array
- C - Multi-Dimensional Arrays
- C - Passing Arrays to Function
- C - Return Array from Function
- C - Variable Length Arrays
- Pointers in C
- C - Pointers
- C - Pointers and Arrays
- C - Applications of Pointers
- C - Pointer Arithmetics
- C - Array of Pointers
- C - Pointer to Pointer
- C - Passing Pointers to Functions
- C - Return Pointer from Functions
- C - Function Pointers
- C - Pointer to an Array
- C - Pointers to Structures
- C - Chain of Pointers
- C - Pointer vs Array
- C - Character Pointers and Functions
- C - NULL Pointer
- C - void Pointer
- C - Dangling Pointers
- C - Dereference Pointer
- C - Near, Far and Huge Pointers
- C - Initialization of Pointer Arrays
- C - Pointers vs. Multi-dimensional Arrays
- Strings in C
- C - Strings
- C - Array of Strings
- C - Special Characters
- C Structures and Unions
- C - Structures
- C - Structures and Functions
- C - Arrays of Structures
- C - Self-Referential Structures
- C - Lookup Tables
- C - Dot (.) Operator
- C - Enumeration (or enum)
- C - Structure Padding and Packing
- C - Nested Structures
- C - Anonymous Structure and Union
- C - Unions
- C - Bit Fields
- C - Typedef
- File Handling in C
- C - Input & Output
- C - File I/O (File Handling)
- C Preprocessors
- C - Preprocessors
- C - Pragmas
- C - Preprocessor Operators
- C - Macros
- C - Header Files
- Memory Management in C
- C - Memory Management
- C - Memory Address
- C - Storage Classes
- Miscellaneous Topics
- C - Error Handling
- C - Variable Arguments
- C - Command Execution
- C - Math Functions
- C - String Functions
- C - Static Keyword
- C - Random Number Generation
- C - Command Line Arguments
C Programming - C Error Handling
![]() Share with a Friend |
C Programming - C Error Handling
Error Handling in C
Error handling is an important aspect of writing robust and stable C programs. In C, error handling can be done in several ways, depending on the type of error (runtime, logical, or system errors). While C doesn't have built-in exception handling mechanisms like some other languages (e.g., C++ or Java), it provides several ways to detect and handle errors effectively.
Common Methods for Error Handling in C
- Return Codes (Error Codes)
- Standard Library Functions (errno)
- assert() Macro
- Error Handling with setjmp() and longjmp()
- Custom Error Handling (using exit() and abort())
- Return Codes (Error Codes)
One of the simplest ways to handle errors in C is to use return codes from functions to indicate success or failure. The function returns a specific value (often an integer) where 0 typically indicates success, and non-zero values indicate different types of errors.
Example:
C
#include <stdio.h>
int divide(int a, int b) {
if (b == 0) {
return -1; // Error: Division by zero
}
return a / b; // Success: Return the result of division
}
int main() {
int result = divide(10, 0);
if (result == -1) {
printf("Error: Division by zero.\n");
} else {
printf("Result: %d\n", result);
}
return 0;
}
- Pros: Simple to implement.
- Cons: Error codes can be hard to manage and track in large programs, especially if there are many possible errors.
- Standard Library Functions (errno)
The C Standard Library provides the errno variable, which is used to set an error code when a system call or library function fails. Many C standard library functions, like fopen(), malloc(), read(), and others, will set errno to indicate the specific error.
The errno.h header defines a set of error codes, and you can use the perror() or strerror() function to print a description of the error.
Example:
C
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main() {
FILE *file = fopen("nonexistentfile.txt", "r");
if (file == NULL) {
// Print the error description using perror
perror("Error opening file");
// Alternatively, use strerror with errno
printf("Error: %s\n", strerror(errno));
}
return 0;
}
Common errno values:
- ENOMEM: Out of memory.
- EINVAL: Invalid argument.
- ENOENT: No such file or directory.
- EIO: I/O error.
- Pros: Useful for system-level errors, standard for error reporting.
- Cons: Needs to be manually checked, and errno should be checked immediately after the function call, as it may be overwritten by subsequent library calls.
- assert() Macro
The assert() macro is used to detect logical errors in the program during debugging. If the expression passed to assert() is false, the program will terminate, and an error message will be printed that indicates the failed condition and the location of the error.
Example:
C
#include <stdio.h>
#include <assert.h>
int divide(int a, int b) {
assert(b != 0); // Check that b is not zero
return a / b;
}
int main() {
int result = divide(10, 0); // This will cause the program to terminate
return 0;
}
Output:
Assertion failed: b != 0, file error.c, line 6
- Pros: Great for debugging and detecting bugs during development.
- Cons: The program is terminated immediately, so it’s not suitable for production error handling. Assertions are typically disabled in release builds (NDEBUG macro).
- Error Handling with setjmp() and longjmp()
The setjmp() and longjmp() functions can be used for non-local jumps, which is a form of error handling that can simulate exceptions. setjmp() sets a point in the program to which execution can jump, and longjmp() is used to jump back to the point set by setjmp(), typically for error recovery.
Example:
C
#include <stdio.h>
#include <setjmp.h>
jmp_buf env;
void handle_error() {
printf("An error occurred, jumping back to main...\n");
longjmp(env, 1); // Jump back to the point saved by setjmp
}
int main() {
if (setjmp(env) == 0) {
// Initial point, no error yet
printf("Program started...\n");
handle_error(); // Simulate an error
} else {
// Error handling after jumping
printf("Program recovered from error.\n");
}
return 0;
}
Output:
Program started...
An error occurred, jumping back to main...
Program recovered from error.
- Pros: Allows for error recovery in certain scenarios.
- Cons: Complex to use, can make the program flow difficult to understand, and it’s typically avoided in production code.
- Custom Error Handling (Using exit() and abort())
C provides the exit() function to terminate a program, typically used in cases where the program cannot continue due to a critical error. The abort() function immediately terminates the program and generates a core dump (useful for debugging).
- exit(): Used to terminate the program, but before terminating, it cleans up the program resources and calls functions registered with atexit().
- abort(): Used to immediately terminate the program without cleanup.
Example:
C
#include <stdio.h>
#include <stdlib.h>
int main() {
int num = -1;
if (num < 0) {
printf("Error: Invalid number.\n");
exit(1); // Exit the program with error code 1
}
printf("Valid number: %d\n", num);
return 0;
}
- Pros: Allows for clean program termination.
- Cons: Stops the program abruptly, making it unsuitable for some scenarios where recovery is needed.
Summary of Error Handling Techniques
| Technique | Description | Use Case |
|---|---|---|
| Return Codes |
Functions return an error code to indicate success or failure. |
Simple functions where failure is rare. |
| errno |
Provides error codes from system calls and standard library. |
For handling system-level errors. |
| assert() |
Used for debugging purposes to detect logical errors. |
Debugging phase. |
| setjmp() / longjmp() |
Allows for error recovery with non-local jumps. |
Complex error handling and recovery. |
| exit() / abort() |
Terminates the program when a critical error occurs. |
Critical errors where recovery isn’t possible. |
Best Practices for Error Handling in C
- Always check return values of system calls and library functions.
- Use errno for system-level errors and provide informative error messages with perror() or strerror().
- Use assert() for debugging to catch logical errors early in the development phase.
- Avoid using longjmp() for general error handling due to its complexity.
- Use exit() or abort() only for critical errors where recovery is not possible.
