C
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Functions
-
Section 4: Arrays and Strings
-
Section 5: Pointers
-
Section 6: Memory Management
-
Section 7: Structures and Unions
-
Section 8: The Preprocessor and Build Process
-
Section 9: Standard Library: stdio.h
-
Section 10: Standard Library: stdlib.h
-
Section 11: Standard Library: string.h
-
Section 12: Standard Library: ctype.h and wctype.h
-
Section 13: Standard Library: math.h, complex.h, fenv.h, tgmath.h
-
Section 14: Standard Library: Type and Limit Headers
-
Section 15: Standard Library: Error Handling and Debugging
-
Section 16: Standard Library: Localization and Encoding
-
Section 17: Standard Library: time.h
-
Section 18: Standard Library: Concurrency (C11)
-
Section 19: POSIX and System Programming (unistd.h)
-
Section 20: More Data Structures
-
Section 21: Algorithms in C
-
Section 22: Bitwise Operations
-
Section 23: Command-Line Programs
-
Section 24: Debugging and Best Practices
-
Section 25: Compiler and Language Internals
-
Section 26: Embedded and Cross-Platform Considerations
-
Section 27: Networking Basics
-
Section 28: Practical Projects
-
Section 29: Interview Practice
-
Section 30: C23 Modern Features
-
Section 31: More Practice and Review
49: Arrays of Function Pointers
Imagine you're designing a simple calculator. You've got buttons for addition, subtraction, multiplication, and division. Now, you could write a massive switch statement that checks which button was pressed and then calls the right function. But if you eventually expand that calculator to support 50 different scientific operations, that switch block becomes a nightmare to read and maintain. It's a wall of boilerplate.
Instead, think of a physical control panel. Each button is wired directly to a specific circuit. When you press button #3, the current doesn't go through a central "decision-maker" that asks, "Are you button 1? No. Button 2? No. Button 3? Yes!"; it just flows straight to the third circuit. In C, an array of function pointers is that control panel. It's a "dispatch table" that lets you jump directly to the logic you need based on an index.
Cleaning up the syntax with typedef
Before we build the array, I want to show you a trick to keep your sanity. Function pointer syntax in C is notoriously ugly. If we define a pointer to a function that takes two doubles and returns a double, it looks like this: double (*ptr)(double, double). If you put that inside an array declaration, it becomes a squint-inducing mess.
I always use a typedef here. It lets us create a shorthand name for the function signature, treating it like a first-class type.
typedef double (*MathOp)(double, double);
Now, MathOp is a type. Any function that matches that signature can be stored in a variable or array of type MathOp. It makes the code read like English instead of a puzzle.
Building the Dispatch Table
Let's map our calculator analogy to actual code. First, we write our individual operation functions. Then, we group them into an array. The magic happens because the array stores the memory addresses of these functions.
#include <stdio.h>
typedef double (*MathOp)(double, double);
double add(double a, double b) { return a + b; }
double subtract(double a, double b) { return a - b; }
double multiply(double a, double b) { return a * b; }
double divide(double a, double b) { return (b != 0) ? a / b : 0; }
int main() {
// This is our "control panel"
MathOp operations[] = { add, subtract, multiply, divide };
double x = 10.0, y = 5.0;
int choice = 2; // Let's say the user pressed the 'multiply' button
// No switch statement needed. We just index into the array.
double result = operations[choice](x, y);
printf("Result: %f\n", result);
return 0;
}
Why this actually matters in the real world
You might be thinking, "I can just use a switch for four functions." You're right. But I've worked on embedded systems and game engines where we had hundreds of different "state" handlers or command packets coming over a network. Using a dispatch table turns an O(n) search (checking every case) into an O(1) lookup.
It also makes your code "pluggable." If you want to add a new operation, you don't have to touch the logic that executes the operation; you just add a new function and drop it into the array. The execution code remains untouched, which is a huge win for stability.
One word of caution: always validate your index. If your array has 4 functions and you try to call operations[10](x, y), you're jumping into random memory, and your program will crash spectacularly. I've been there; it's not a fun way to spend a Friday afternoon.
📋 Practical Task
Building a Text-Adventure Command Processor
Your task is to move away from if/strcmp chains and implement a command processor for a text-adventure game using an array of function pointers.
Requirements:
- Create a
typedeffor a function that takes no arguments and returnsvoid. - Implement at least four functions:
look(),inventory(),north(), andquit(). Each should simply print a descriptive message to the console. - Create an array of these function pointers.
- In
main(), simulate a user inputting a number (0-3) to select a command. Use that number as an index to call the corresponding function from your array. - Include a bounds check to ensure the user doesn't provide an index outside the array range.
There are no comments for now.