Указатель на voidэто «универсальный» тип указателя. A void *может быть преобразован в любой другой тип указателя без явного приведения. Вы не можете разыменовывать void *или делать арифметику указателей с ним; Вы должны сначала преобразовать его в указатель на полный тип данных.
void *часто используется в местах, где вам нужно иметь возможность работать с разными типами указателей в одном и том же коде. Одним из часто цитируемых примеров является функция библиотеки qsort:
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
baseэто адрес массива, nmembэто количество элементов в массиве, sizeэто размер каждого элемента, иcompar является указателем на функцию, которая сравнивает два элемента массива. Это называется так:
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);
Выражения массива iArr, dArrи lArrнеявно преобразуется из типов массивов для типов указателей в вызове функции, и каждый неявно преобразуются из «указателя int/double / long» в «указатель void».
Функции сравнения будут выглядеть примерно так:
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;
}
Принимая void * , qsortможно работать с массивами любого типа.
Недостаток использования void * заключается в том, что вы выбрасываете безопасность типов в окно и во встречный трафик. Там нет ничего, чтобы защитить вас от использования неправильной процедуры сравнения:
qsort(dArr, sizeof dArr/sizeof dArr[0], sizeof dArr[0], compareInt);
compareIntожидает, что его аргументы будут указывать на ints, но на самом деле работает с doubles. Нет способа поймать эту проблему во время компиляции; вы просто получите пропущенный массив.