← Back to C Course | Chapter 12: Advanced Topics | Lesson 16 of 20

C Error Handling

Error handling is checking whether things worked and planning what to do when they do not, like having a spare tire. It keeps one problem from ruining everything.
Syntax
c
if (function_name(arguments) == error_value) {
  // handle the failure
}

if (divisor == 0) {
  // avoid dividing by zero
}

Checking Return Values

Standard library functions signal failure through their return value — often NULL for a pointer-returning function or -1 for an integer-returning one — so checking that return value immediately after the call is the most basic and most frequently skipped error-handling habit in C.

Example: Checking Return Values

c
// Include standard input/output (printf, scanf)
#include <stdio.h>
// Program execution starts in main()
int main() {
	FILE *fp = fopen("nonexistent.txt", "r");
	// Check whether fp == NULL
	if (fp == NULL) {
		// Print formatted text to the screen
		printf("Failed to open");
		// Send 1 back to the caller
		return 1;
	}
	fclose(fp);
	// Return 0 to signal that the program finished successfully
	return 0;
}

Handling Division by Zero

C performs no automatic check for division by zero, so dividing an integer by a variable that happens to be zero crashes the program (or, for floating-point division, produces inf or nan) rather than raising a catchable exception.

Validating a divisor with a plain if before dividing is the only reliable defense.

Example: Handling Division by Zero

c
// Include standard input/output (printf, scanf)
#include <stdio.h>
// Program execution starts in main()
int main() {
	int a = 10, b = 0;
	// Check whether b == 0
	if (b == 0) {
		// Print formatted text to the screen
		printf("Cannot divide by zero");
	} else {
		// Print formatted text to the screen
		printf("%d", a / b);
	}
	// Return 0 to signal that the program finished successfully
	return 0;
}

Handling Allocation Failures

When dynamic memory is exhausted, malloc() and its relatives return NULL instead of a valid pointer, and writing through that NULL pointer without checking for it first crashes the program.

Always test the return value of an allocation call before using the memory it was supposed to provide.

Example: Handling Allocation Failures

c
// Include standard input/output (printf, scanf)
#include <stdio.h>
// Include general utilities (malloc, free, exit)
#include <stdlib.h>
// Program execution starts in main()
int main() {
	// Allocate memory on the heap
	int *ptr = malloc(sizeof(int));
	// Check whether ptr == NULL
	if (ptr == NULL) {
		// Print formatted text to the screen
		printf("Allocation failed");
		// Send 1 back to the caller
		return 1;
	}
	*ptr = 5;
	// Print formatted text to the screen
	printf("%d", *ptr);
	free(ptr);
	return 0;
}

Setting Fallback Defaults

When an operation can plausibly fail but the program can still make progress, falling back to a sensible default value (rather than propagating garbage or an uninitialized value) keeps execution stable instead of letting one bad reading corrupt everything downstream.

Example: Setting Fallback Defaults

c
// Include standard input/output (printf, scanf)
#include <stdio.h>
// Program execution starts in main()
int main() {
	// Declare userInput and set it to -1
	int userInput = -1;
	int value = (userInput < 0) ? 0 : userInput;
	// Print formatted text to the screen
	printf("%d", value);
	// Return 0 to signal that the program finished successfully
	return 0;
}

Graceful Termination

When an error truly can't be recovered from, exiting cleanly with a non-zero status code (typically via exit(1) or a non-zero return from main) tells any calling shell script or parent process that something went wrong, which matters for automation that checks a program's exit status.

Example: Graceful Termination

c
// Include standard input/output (printf, scanf)
#include <stdio.h>
// Include general utilities (malloc, free, exit)
#include <stdlib.h>
// Program execution starts in main()
int main() {
	// Declare criticalError and set it to 1
	int criticalError = 1;
	// Check whether criticalError
	if (criticalError) {
		// Print formatted text to the screen
		printf("Unrecoverable error");
		exit(1);
	}
	// Return 0 to signal that the program finished successfully
	return 0;
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Ignoring return values of functions such as fopen and malloc.
  2. Not checking the result of malloc before using the pointer.
  3. Not checking for a zero divisor before dividing, which is undefined behavior for integers.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.