Advanced Pointers

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.

x10*p&x**pp&p

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 qsort function from the standard library uses void * 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.