Chapter 12: Advanced Pointers
Once you understand basic pointers, you can explore the advanced techniques that make C the primary language for systems architecture. This includes levels of indirection, function pointers, and generic pointers.
I. Double Pointers (Pointers to Pointers)
A double pointer stores the memory address of another pointer.
int x = 10;
int *p = &x;
int **pp = &p; // pp stores the address of p
Use Case: Modifying a Pointer Inside a Function
If you want a function to change where a pointer points (e.g., in a linked list insertion), you must pass a pointer to the pointer.
II. Function Pointers
In C, functions themselves have addresses in the Text Segment. A function pointer allows you to pass logic as an argument to another function (Callbacks).
// Declaration: return_type (*pointer_name)(parameter_types);
void say_hello() { printf("Hello!\n"); }
void execute(void (*func)()) {
func(); // Call via pointer
}
int main() {
execute(say_hello);
return 0;
}
III. void * (The Generic Pointer)
A void * can store the address of any data type. It is the foundation for polymorphism and generic programming in C.
- Limitation: You cannot dereference a
void *directly. You must cast it to a specific type first. - Example: The
qsortfunction from the standard library usesvoid *to sort any type of array.
int x = 10;
void *p = &x;
printf("%d\n", *(int *)p); // Cast and dereference
IV. Pointers vs. Arrays
An array name is essentially a constant pointer to its first element.
arr[i]is exactly the same as*(arr + i).- The compiler converts all array indexing to pointer arithmetic.
V. Opaque Pointers
Opaque pointers are used to hide the internal implementation of a data structure. The user is given a pointer to a struct, but the struct's definition is not provided in the header file. This provides encapsulation in C.
VI. Function Pointer Tables (Jump Tables)
By creating an array of function pointers, you can replace complex switch statements with an O(1) jump table. This is common in compiler design and hardware drivers.
void (*ops[])(int, int) = { add, sub, mul, div };
ops[choice](a, b); // Executes the chosen operation
Advanced pointers allow you to build sophisticated systems. However, they also introduce the risk of memory corruption if not handled carefully.