Un puntero a voides un tipo de puntero "genérico". A void *se puede convertir a cualquier otro tipo de puntero sin una conversión explícita. No puede desreferenciar void *ni hacer aritmética de puntero con él; primero debe convertirlo en un puntero a un tipo de datos completo.
void *a menudo se usa en lugares donde necesita poder trabajar con diferentes tipos de puntero en el mismo código. Un ejemplo comúnmente citado es la función de biblioteca qsort:
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
basees la dirección de una matriz, nmembes el número de elementos en la matriz, sizees el tamaño de cada elemento y compares un puntero a una función que compara dos elementos de la matriz. Se llama así:
int iArr[10];
double dArr[30];
long lArr[50];
...
qsort(iArr, sizeof iArr/sizeof iArr[0], sizeof iArr[0], compareInt);
qsort(dArr, sizeof dArr/sizeof dArr[0], sizeof dArr[0], compareDouble);
qsort(lArr, sizeof lArr/sizeof lArr[0], sizeof lArr[0], compareLong);
Las expresiones de matriz iArr, dArry lArrse convierten implícitamente a partir de los tipos de matriz a los tipos de puntero en la llamada de función, y cada uno se convierten implícitamente de "puntero a int/ double/ long" a "puntero a void".
Las funciones de comparación se verían así:
int compareInt(const void *lhs, const void *rhs)
{
const int *x = lhs; // convert void * to int * by assignment
const int *y = rhs;
if (*x > *y) return 1;
if (*x == *y) return 0;
return -1;
}
Al aceptar void *, qsortpuede trabajar con matrices de cualquier tipo.
La desventaja de usar void *es que arrojas la seguridad de tipografía por la ventana y hacia el tráfico que viene. No hay nada que lo proteja de usar la rutina de comparación incorrecta:
qsort(dArr, sizeof dArr/sizeof dArr[0], sizeof dArr[0], compareInt);
compareIntespera que sus argumentos apunten a ints, pero en realidad está trabajando con doubles. No hay forma de detectar este problema en tiempo de compilación; terminarás con una matriz mal ordenada.