TRT
Sign in
easyFoundationsconcept

How does void * enable generic functions like memcpy and qsort in C, and what are the rules for using void * and NULL safely?

Explain implicit object-pointer conversion to and from void *, why void * cannot be dereferenced directly, and how generic callbacks use element size.

TRT practice prompt — not a verified question from a named employer.

The Runtime Theory Team2 min read
Learn it firstGeneric Pointers and Null Pointer MechanicsMaster type erasure with void pointers, understand null pointer representation and MMU zero-page guard traps, and handle raw memory safely.

A strong answer

Because C does not have templates or generics, it uses void * as its universal generic object pointer. Any object pointer (int *, struct node *, char *) converts to void * and back again implicitly without a cast in C. That allows functions like malloc(size_t size), memcpy(void *dst, const void *src, size_t n), and qsort(void *base, size_t nmemb, size_t size, int (*cmp)(const void *, const void *)) to operate on memory buffers of any type.

However, because void is an incomplete type with no known size or layout, the compiler forbids two operations directly on a void *:

  1. You cannot dereference *vp (the CPU would not know how many bytes to read).
  2. You cannot perform pointer arithmetic vp + 1 in standard C (the compiler does not know the element stride).

To see how qsort sorts an arbitrary array through void *base, notice that the caller passes both nmemb (element count) and size (sizeof(element)). Internally, qsort casts base to unsigned char * (1-byte stride), computes the address of element i as (unsigned char *)base + i * size, and passes those element pointers as const void * to your comparison callback, which casts them back to const int * (or your struct type) before dereferencing.

What the interviewer is listening for

  • Explains that void * holds a raw memory address without type width, requiring explicit conversion to a concrete type before dereferencing and unsigned char * + size for generic element indexing.
  • Knows that NULL represents a pointer guaranteed not to point to any valid object, and dereferencing NULL triggers a hardware page fault on page 0x0.
  • Mentions that in C (unlike C++), void * converts implicitly to any object pointer, so casting malloc is unnecessary.

Common mistakes

  • Dereferencing a void * without first assigning or casting it to a typed pointer.
  • Violating alignment requirements by casting an unaligned void * (e.g., 0x1001) to uint64_t * and dereferencing it.
  • Assuming void * is guaranteed by the C standard to hold function pointers (POSIX requires dlsym to work with void *, but strict ISO C allows function pointers on Harvard architectures to have a different width than object pointers).

This answer walks

Practice follow-ups

  1. 01Why can't you pass a function pointer to a parameter typed as void * in strict ISO C?
  2. 02Why does malloc return void * instead of char *, and why shouldn't you cast malloc's return value in C?

Not started

Sign in to save your learning progress.

Sign in to save