Pointers to the Void: Advanced C Tricks
In C, the void* pointer is both the most powerful and the most dangerous tool in a programmer's arsenal. It represents raw, untyped memory — a gateway to generic programming in a language that has no generics.
The Nature of void*
A void* can hold the address of any data type. It is the lingua franca of C APIs, used in qsort(), bsearch(), pthread_create(), and countless other standard library functions.
void swap(void *a, void *b, size_t size) {
char temp[size];
memcpy(temp, a, size);
memcpy(a, b, size);
memcpy(b, temp, size);
}
Function Pointers: Code as Data
Function pointers allow you to store and pass around references to executable code. Combined with void* for data, this pattern enables polymorphism in C.
typedef int (*Comparator)(const void*, const void*);
int compare_int(const void *a, const void *b) {
return (*(int*)a - *(int*)b);
}
// Usage with qsort
qsort(array, n, sizeof(int), compare_int);
Building a Generic Container
With void* and function pointers, you can build type-erased containers that rival C++ templates in functionality (though not in type safety).
typedef struct {
void **items;
size_t count;
size_t capacity;
size_t item_size;
void (*destructor)(void*);
} GenericArray;
The Dangers of the Void
With great power comes great responsibility. Unsafe casts through void* bypass the type system entirely. A wrong cast is silent at compile time but catastrophic at runtime. Always document your void* contracts explicitly.
The void is not empty — it is full of potential. Navigate it carefully.
