Void Pointers & Generics
How C achieves type-agnostic code with void* — and why you must cast before use
Quick check before you start: In Java,
Objectis the root of every class — you can store anything as anObjectreference. C’svoid*serves the same role. Read on.Practice this topic: Void Pointers skill drill
After this lesson, you will be able to:
- Explain what
void*means and why it exists - Cast a
void*to a typed pointer before dereferencing - Describe how
qsortusesvoid*to sort any type - Compare
void*to Java’sObjecttype
What Is void*?
A void* is a pointer with no type information. It holds a memory address, but the compiler does not know what lives at that address.
int x = 42;
void *ptr = &x; // legal — any pointer can become void*
You can assign any pointer to a void* without a cast. But you cannot dereference it directly:
printf("%d\n", *ptr); // COMPILER ERROR — what type is *ptr?
The compiler does not know whether to read 1 byte, 4 bytes, or 8 bytes. You must cast first.
Casting Before Dereference
To use the data behind a void*, cast it to the correct type:
int x = 42;
void *ptr = &x;
int *iptr = (int*)ptr;
printf("%d\n", *iptr); // prints 42
If you cast to the wrong type, you get garbage or a crash. The compiler cannot check this for you. The responsibility is yours.
How qsort Uses void*
Look at qsort’s signature:
void qsort(void *base, size_t count, size_t size,
int (*cmp)(const void*, const void*));
Every parameter is type-agnostic:
baseisvoid*— it accepts arrays of any typesizetells qsort how many bytes per elementcmpreceivesconst void*pointers — the comparator knows the real type
This is how one function sorts arrays of int, double, char*, or Student — the caller provides the type knowledge through the comparator.
int compare_doubles(const void *a, const void *b) {
double x = *(const double*)a;
double y = *(const double*)b;
if (x < y) return -1;
if (x > y) return 1;
return 0;
}
double arr[] = {3.1, 1.4, 2.7};
qsort(arr, 3, sizeof(double), compare_doubles);
Same qsort, different comparator, different type. That is generic programming in C.
void* Is Java’s Object
| Java | C |
|---|---|
Object |
void* |
Downcast with (String)obj |
Cast with (char*)ptr |
ClassCastException at runtime |
Undefined behavior (no check) |
| Generics add compile-time safety | No equivalent — you just cast correctly |
Java generics are syntactic sugar over Object with compile-time checks. C gives you the raw mechanism without the safety net.
Rules for void*
- Any pointer converts to
void*implicitly — no cast needed - You must cast
void*before dereferencing — the compiler does not know the type - You cannot do pointer arithmetic on
void*— the compiler does not know the element size - Casting to the wrong type is undefined behavior — there is no runtime check
void* before dereferencing it?void* carries no type information. The compiler needs to know whether to read 1 byte (char), 4 bytes (int), 8 bytes (double), or something else. Casting tells the compiler the actual type so it can generate the correct dereference instruction.
What Comes Next
You understand void pointers and function pointers separately. Next, you will combine them to build generic data structures — containers that store any type, just like Java’s ArrayList<T>.