🔴 Advanced  ·  Lesson 45

Error Handling in C

How C handles errors

Many modern languages have try and catch for errors. C does not. Instead, C uses a simpler, older approach: a function tells you it failed through its return value, and it is your job to check that value every time.

On top of that, many standard functions set a special global variable called errno that carries a code explaining why they failed. Together, return-value checking and errno are how reliable C programs stay safe.

Checking return values

The core habit is: after calling a function that can fail, immediately check what it returned before using the result.

C Language
#include <stdio.h>
int main() {
    FILE *fp = fopen("data.txt", "r");
    if (fp == NULL) {              // check before using
        printf("Error: could not open file.\n");
        return 1;
    }
    // safe to use fp here
    fclose(fp);
    return 0;
}
Output (if file missing):
Error: could not open file.

errno, perror and strerror

When a standard function fails, it often sets errno. You can print a readable description of it in two ways.

C Language
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main() {
    FILE *fp = fopen("missing.txt", "r");
    if (fp == NULL) {
        perror("fopen failed");              // message + errno text
        printf("Details: %s\n", strerror(errno)); // same, as string
        return 1;
    }
    fclose(fp);
    return 0;
}
Output:
fopen failed: No such file or directory
Details: No such file or directory
💡 Read errno immediately

errno only reflects the last failing call. Check it right away, because the next function call may overwrite it.

Handling file errors

File work is a classic place for errors: the file may be missing, locked, or full. Always check fopen, and check reads and writes too.

C Language
FILE *fp = fopen("data.txt", "w");
if (fp == NULL) {
    perror("Cannot open data.txt");
    return 1;
}
if (fprintf(fp, "Hello\n") < 0) {   // writing can fail too
    perror("Write failed");
}
fclose(fp);

See file handling in C for the full set of file functions.

Handling memory errors

malloc can fail when memory runs out. Using its result without checking is a common crash.

C Language
#include <stdio.h>
#include <stdlib.h>
int main() {
    int *arr = malloc(100 * sizeof(int));
    if (arr == NULL) {                // check!
        printf("Error: out of memory.\n");
        return 1;
    }
    // use arr safely...
    free(arr);
    return 0;
}

See dynamic memory in C for more on malloc and free.

Best practices

  • Check the return value of every function that can fail.
  • Handle the error close to where it happens, with a clear message.
  • Read errno immediately, before another call overwrites it.
  • Free any resources (files, memory) before exiting on an error.
  • Return a non-zero code from main to signal failure to the system.

Common mistakes

  • Ignoring return values and using a NULL or invalid result.
  • Reading errno too late, after another call has changed it.
  • Printing an error but then continuing as if nothing failed.
  • Leaking files or memory by returning early without cleanup.
🏋️ Practice

Write a program that tries to open a file the user names. If it fails, use perror to show why, and return a non-zero exit code. Test it with a real file and a missing file.

Summary

  • C has no exceptions — errors are reported through return values.
  • Many functions set errno; read it right after the failing call.
  • perror prints an error message; strerror returns it as a string.
  • Always check fopen, malloc, reads and writes.
  • Clean up resources and return a non-zero code on failure.

Frequently Asked Questions

How does error handling work in C?
C has no built-in exceptions like try/catch. Instead, functions report problems through their return value — for example returning NULL or -1 on failure — and you check that value after every call. Many library functions also set a global variable called errno with a code describing what went wrong.
What is errno in C?
errno is a global variable defined in <errno.h> that many standard functions set when they fail. It holds a number identifying the specific error. You read it right after a failing call, and you can turn it into a readable message with perror or strerror.
What is the difference between perror and strerror?
perror("msg") prints your message followed by the text for the current errno, straight to standard error. strerror(errno) instead returns that error text as a string, so you can print it yourself or put it in a log. They describe the same error in different forms.
Does C have try and catch like other languages?
No. C has no exceptions or try/catch. Error handling is done manually by checking return values and errno. For jumping out of deep error situations there is setjmp/longjmp, but everyday C code relies on checking each function's result.
Why should I always check the return value of malloc and fopen?
Because both can fail — malloc returns NULL if memory runs out, and fopen returns NULL if the file cannot be opened. If you use the result without checking, the program will likely crash. Checking lets you print a clear message and exit safely instead.
← Back to C Tutorial
🔗

Share this topic with a friend

यह topic किसी दोस्त को भेजें

Found it useful? Send it to a classmate learning the same thing.

अच्छा लगा? जो दोस्त यही सीख रहा है, उसे भेज दीजिए।

💻 Live Code Editor

This page's programs are ready here — run them, edit them, and learn. No installation needed.
Powered by OneCompiler. The code loads into the editor automatically — press Run to see the output. If the editor does not open, open it in a new tab.