Un puntatore a voidè un tipo di puntatore "generico". A void *può essere convertito in qualsiasi altro tipo di puntatore senza un cast esplicito. Non puoi dereferenziare void *o eseguire l'aritmetica del puntatore con esso; devi prima convertirlo in un puntatore in un tipo di dati completo.
void *viene spesso utilizzato in luoghi in cui è necessario poter lavorare con diversi tipi di puntatore nello stesso codice. Un esempio comunemente citato è la funzione di libreria qsort:
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
baseè l'indirizzo di un array, nmembè il numero di elementi nell'array, sizeè la dimensione di ciascun elemento ed comparè un puntatore a una funzione che confronta due elementi dell'array. Si chiama così:
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);
Le espressioni di matrice iArr, dArre lArrsono implicitamente convertiti da tipi array di tipi di puntatore nella chiamata di funzione, e ciascuno è implicitamente convertito da "puntatore a int/ double/ long" a "puntatore void".
Le funzioni di confronto sarebbero simili a:
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;
}
Accettando void *, qsortpuò lavorare con array di qualsiasi tipo.
Lo svantaggio dell'utilizzo void *è che si lancia la sicurezza del tipo fuori dalla finestra e nel traffico in arrivo. Non c'è nulla che ti protegga dall'utilizzare la routine di confronto sbagliata:
qsort(dArr, sizeof dArr/sizeof dArr[0], sizeof dArr[0], compareInt);
compareIntsi aspetta che i suoi argomenti puntino a ints, ma in realtà sta lavorando con doubles. Non c'è modo di risolvere questo problema in fase di compilazione; ti ritroverai con un array distorto.