It is sometimes necessary to store or pass pointers without knowing what type they point to. For this, you can use the generic pointer type void *. You can convert between the generic pointer type and other pointer types (except pointer-to-function types) whenever you need to:

int x;
int *xp, *yp;
void *vp;

xp = &x;

vp = xp;   /* Types are compatible. */

/* later... */

yp = vp;   /* Types are compatible. */

A generic pointer cannot be dereferenced, nor can pointer arithmetic be applied to it.

x = *vp;  /* error: cannot dereference void * */
vp++;     /* error: cannot do arithmetic on void * */

The generic pointer type simply allows you to tell the compiler that you're taking responsibility for a pointer's interpretation, and so no error messages or warnings are to be reported when assigning. It is the programmer's responsibility to ensure that the pointer value is interpreted as the correct type.

int *ip;
float *fp;
void *vp;

fp = ip;  /* error: incompatible types */
vp = ip;  /* okay */
fp = vp;  /* no compiler error, but is misuse */

Generic pointers are used with dynamic memory management, among other things.