Void Pointer in C – Why *(int *)vp Works and *vp Fails

A void pointer is C’s “points at anything” type — it can hold the address of an int, a struct, or a buffer, but it deliberately forgets the type along the way. This question from our C Programming Quiz App tests the round trip: store an address in a void *, cast it back, dereference. Is that valid C, an error, or undefined behavior?

The Quiz Question

int x = 42;
void *vp = &x;
printf("%d", *(int *)vp);

What is printed by this code?

  1. 42
  2. Address of x
  3. Compile error
  4. Undefined behavior

The Correct Answer: 42

The assignment void *vp = &x needs no cast — in C, any object pointer converts to void * and back implicitly. The expression *(int *)vp first casts vp back to int *, then dereferences, reading the original 42. The standard guarantees this round trip: converting a pointer to void * and back to the original type yields a pointer that compares equal to the original (C11 §6.3.2.3). Verified on gcc 13.3 and Apple clang 21, clean under -Wall -Wextra:

$ gcc -Wall -Wextra voidp.c && ./a.out
42

Why Each Wrong Answer Is Wrong

Why not “Address of x”?

The star at the front is doing its job: (int *)vp is the address, but *(int *)vp dereferences it. To print the address you’d write printf("%p", vp) — no cast needed there, since %p expects void * exactly.

Why not “Compile error”?

The cast is precisely what keeps this legal. What actually fails to compile is dereferencing the void * directly — void is an incomplete type, so there’s no object size or type to read:

printf("%d", *vp);    /* no cast: constraint violation */
$ gcc -Wall -Wextra bad.c
bad.c:5:20: warning: dereferencing 'void *' pointer
bad.c:5:20: error: invalid use of void expression

$ clang bad.c
bad.c:5:20: error: argument type 'void' is incomplete

So this option contains a real rule — it just applies to *vp, not to *(int *)vp.

Why not “Undefined behavior”?

Casting back to the original type is the defined, guaranteed direction. UB would enter if you cast to a different, incompatible type — say *(float *)vp — which violates strict aliasing and may also break alignment rules. Round-tripping through void * to the exact type you started with is the pattern the standard exists to support.

Why void * Exists: Generic Interfaces

The whole C memory API runs on this mechanism. malloc returns void * because it can’t know what you’ll store; the implicit conversion means no cast is needed in C:

int *arr = malloc(10 * sizeof *arr);   /* void* → int* implicitly */

Likewise memcpy, qsort‘s comparison callbacks, and thread start routines (pthread_create) all traffic in void * so one function can serve every type. The discipline that keeps it safe is exactly what the quiz encodes: whoever takes the pointer out must cast it back to the type that went in. If that pointed-to memory has meanwhile been freed, you’re in use-after-free territory — the cast can’t save you from a dead target.

Frequently Asked Questions

Can you dereference a void pointer in C?

Not directly — *vp is a compile error because void is incomplete; the compiler has no idea how many bytes to read. Cast to the correct object type first: *(int *)vp.

Do I need to cast the result of malloc in C?

No. void * converts implicitly to any object pointer type in C, so int *p = malloc(n) is idiomatic. (C++ is different — there the cast is required, which is why you sometimes see it in C code written by C++ programmers.)

Is casting a void pointer to the wrong type undefined behavior?

Dereferencing through the wrong type is — it violates strict aliasing, and possibly alignment. The guarantee only covers casting back to the original pointer type (or a compatible one, or char * for byte access).

Related Reading

Recommended Books

This question is #45 in the C Programming Quiz App — 155 questions with explanations covering operators, pointers, memory, and more.
Download on Google Play →

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>