SrcForge

Lesson 26

Error Handling

Error handling in C is the process of detecting, reporting, and responding to errors during program execution. C does not provide built-in exception handling; instead, programmers use return values, error codes, and standard library functions such as perror(), strerror(), errno, exit(), and assert().

C Track

Save progress as you learn.

44 lessons

Lesson content

Error Handling in C Programming: A Complete Beginner to Advanced Guide

What is Error Handling in C Programming?

Error handling is the process of detecting, reporting, and responding to errors that occur during program execution. Unlike some modern programming languages, C does not provide built-in exception handling (try, catch, throw). Instead, programmers handle errors by checking return values, using error codes, and utilizing standard library functions.

For example, when opening a file, the operation may fail if the file does not exist. Your program should detect this failure and respond appropriately instead of crashing.

Think of error handling like a traffic signal. When everything is normal, traffic moves smoothly. When something goes wrong, signals help prevent accidents by directing the correct response.

Why Does Error Handling Exist?

Errors can occur for many reasons, including:

  • Invalid user input
  • File not found
  • Memory allocation failure
  • Division by zero
  • Network failures
  • Hardware problems

Error handling helps to:

  • Prevent program crashes
  • Improve reliability
  • Make debugging easier
  • Provide meaningful error messages
  • Handle unexpected situations gracefully

Real-World Use Cases

Error handling is essential in:

  • Banking systems
  • File management software
  • Operating systems
  • Embedded systems
  • Database applications
  • Network programming
  • Medical software
  • E-commerce applications

Prerequisites

Before learning Error Handling in C Programming, you should understand:

  • Variables
  • Functions
  • Input and output
  • Pointers
  • File handling
  • Dynamic memory allocation

Core Concepts of Error Handling in C Programming

Types of Errors in C

Error TypeDescription
Syntax ErrorsErrors detected during compilation
Runtime ErrorsErrors that occur while the program is running
Logical ErrorsErrors that produce incorrect results without crashing

Compile-Time Errors

These errors occur before the program executes.

int number

printf("%d", number);

Error: Missing semicolon (;).

Runtime Errors

Runtime errors occur while the program is executing. Examples include:

  • Dividing by zero
  • Accessing invalid memory
  • Opening a missing file
  • Memory allocation failure

Logical Errors

Logical errors occur when the program runs successfully but produces incorrect output.

int area = length + width;

Correct formula:

int area = length * width;

Error Handling Functions

C provides several standard library functions and mechanisms for handling errors.

FunctionHeader FilePurpose
perror()<stdio.h>Prints a descriptive error message
strerror()<string.h>Returns a human-readable error string
errno<errno.h>Stores the last error code
exit()<stdlib.h>Terminates the program
assert()<assert.h>Detects programming errors during development

The errno Variable

errno is a global variable set by many library functions when an error occurs.

#include <errno.h>

printf("%d", errno);

Always check whether the function actually failed before inspecting errno, because not every successful call resets it.

Using perror()

The perror() function prints a custom message followed by a description of the current error.

Syntax

perror("message");

Using strerror()

The strerror() function converts an error number into a readable message.

printf("%s", strerror(errno));

Using exit()

The exit() function terminates the program immediately.

Syntax

exit(status);

Common status values:

ValueMeaning
EXIT_SUCCESSSuccessful termination
EXIT_FAILUREAbnormal termination

Using assert()

The assert() macro helps detect programming mistakes during development.

assert(pointer != NULL);

If the condition is false, the program prints diagnostic information and terminates.

Code Examples

Example 1: Beginner – Check Division by Zero

#include <stdio.h>                     // Include standard input/output library

int main(void)                         // Program entry point
{
    int numerator = 20;                // Store the numerator

    int denominator = 0;               // Store the denominator

    if (denominator == 0)              // Check whether division is valid
    {
        printf("Error: Division by zero is not allowed.\n"); // Print an error message

        return 1;                      // Return a non-zero status
    }

    printf("%d\n", numerator / denominator); // Perform division

    return 0;                          // End the program
}

Example 2: Beginner – Handle File Opening Errors

#include <stdio.h>                     // Include standard input/output library

int main(void)                         // Program entry point
{
    FILE *file = fopen("data.txt", "r"); // Attempt to open the file

    if (file == NULL)                  // Check whether opening failed
    {
        perror("File Error");          // Print the system error message

        return 1;                      // Exit with an error
    }

    printf("File opened successfully.\n"); // Print a success message

    fclose(file);                      // Close the file

    return 0;                          // End the program
}

Example 3: Intermediate – Using errno and strerror()

#include <stdio.h>                     // Include standard input/output library
#include <errno.h>                     // Include error number definitions
#include <string.h>                    // Include strerror()

int main(void)                         // Program entry point
{
    FILE *file = fopen("sample.txt", "r"); // Attempt to open a file

    if (file == NULL)                  // Check whether opening failed
    {
        printf("Error Code: %d\n", errno); // Print the error code

        printf("Message: %s\n", strerror(errno)); // Print the error description

        return 1;                      // Exit with an error
    }

    fclose(file);                      // Close the file

    return 0;                          // End the program
}

Example 4: Intermediate – Check Memory Allocation

#include <stdio.h>                     // Include standard input/output library
#include <stdlib.h>                    // Include memory allocation functions

int main(void)                         // Program entry point
{
    int *ptr = (int *)malloc(1000000000 * sizeof(int)); // Request a large memory block

    if (ptr == NULL)                   // Check whether allocation failed
    {
        printf("Memory allocation failed.\n"); // Print an error message

        return 1;                      // Exit with an error
    }

    printf("Memory allocated successfully.\n"); // Print a success message

    free(ptr);                         // Release the memory

    return 0;                          // End the program
}

Example 5: Advanced – Using assert()

#include <stdio.h>                     // Include standard input/output library
#include <assert.h>                    // Include assert()

int main(void)                         // Program entry point
{
    int *ptr = NULL;                   // Declare a null pointer

    assert(ptr != NULL);               // Verify that the pointer is not NULL

    printf("Pointer is valid.\n");     // This line will not execute if the assertion fails

    return 0;                          // End the program
}

Note: Assertions are intended for debugging and development. They can be disabled by defining NDEBUG before including <assert.h>.

Common Mistakes and Pitfalls

WrongCorrect
Ignoring function return valuesAlways check whether a function succeeded
Calling fclose() on a NULL file pointerClose the file only if it was opened successfully
Assuming memory allocation always succeedsCheck if the returned pointer is NULL
Using assert() for user input validationUse normal error handling for runtime conditions
Printing generic error messagesProvide meaningful, descriptive messages

Wrong:

FILE *file = fopen("data.txt", "r");

fclose(file);

Correct:

FILE *file = fopen("data.txt", "r");

if (file != NULL)
{
    fclose(file);
}
else
{
    perror("Unable to open file");
}

Best Practices

  • Always check the return values of library functions.
  • Use perror() or strerror() to display meaningful error messages.
  • Validate user input before processing it.
  • Release allocated memory even when errors occur.
  • Close files after use.
  • Return appropriate status codes from functions.
  • Use assert() to detect programming errors during development, not for handling expected runtime errors.
  • Write clear error messages that help users and developers understand the problem.

When NOT to Use This

Avoid certain error-handling approaches in these situations:

  • Don't use assert() to validate user input or file existence; handle these conditions normally.
  • Don't terminate the program with exit() for every minor error if recovery is possible.
  • Don't ignore error codes returned by standard library functions.
  • Don't hide errors by silently continuing after a critical failure.

Whenever possible, recover gracefully instead of terminating the program immediately.

Summary / Key Takeaways

  • Error Handling in C programming helps detect and manage problems during program execution.
  • C does not provide built-in exception handling like try and catch.
  • Always check the return values of functions.
  • Use errno to obtain error codes when appropriate.
  • Use perror() and strerror() to display readable error messages.
  • Use exit() to terminate the program when recovery is not possible.
  • Use assert() to detect programming mistakes during development.
  • Good error handling makes programs more reliable, maintainable, and user-friendly.

FAQ About Error Handling in C

1. Does C have exception handling like Java or C++?

No. Standard C does not provide try, catch, or throw. Error handling is performed using return values, error codes, and standard library facilities.

2. What is errno?

errno is a global variable that many library functions set when an error occurs. It stores an error code that can be converted into a readable message using strerror() or displayed with perror().

3. What is the difference between perror() and strerror()?

perror()strerror()
Prints a custom message followed by the system error descriptionReturns a pointer to the error description as a string
Writes directly to the standard error streamLets you format or process the message yourself

4. When should I use assert()?

Use assert() during development to detect programming mistakes, such as invalid assumptions or impossible conditions. It should not be used to handle expected runtime errors like invalid user input.

5. Why should I always check function return values?

Many C library functions indicate success or failure through their return values. Checking these values allows your program to detect errors early, avoid undefined behavior, and respond appropriately.