Um ponteiro para void é um ponteiro que não tem nenhum tipo de dado associado com ele. Um void pointer pode conter o endereço qualquer tipo de dado e pode ser convertido para qualquer tipo.
Exemplo:
int a = 10;
char b = 'x';
void *p = &a; // o void pointer 'p' contem o endereço do int 'a'
p = &b; // o void pointer 'p' contem o endereço do char 'b'
Vantagens
- malloc() e calloc() retornam o tipo void * e isso permite que essas funções possam ser usadas para alocar memória de qualquer tipo de dado.
- Ponteiros para void em C são usados para implementar funções genéricas.
Alguns fatos interessantes
- void * não podem ser desreferenciados. Por exemplo, o seguinte programa não compila.
#include<stdio.h>
int main()
{
int a = 10;
void *ptr = &a;
printf("%d", *ptr);
return 0;
}
Para compilar, devemos alterar printf(“%d”, *ptr) para printf(“%d”, *(int *)ptr).
- O padrão C não permite que operações aritméticas com void pointers. Entretanto, no GNU C é permitido considerando que o tamanho de void é 1. Por exemplo o seguinte programa compila e executa com o gcc.
#include<stdio.h>
int main()
{
int a[2] = {1, 2};
void *ptr = &a;
ptr = ptr + sizeof(int);
printf("%d", *(int *)ptr); //saída: 2
return 0;
}
Quando usar const void *?
Um const void* é um ponteiro para algum dado que não pode ser modificado (por exemplo um const char *). Para manipula-lo é necessário fazer um type casting.
Qual a diferença de um void * para um ponteiro nulo?
Um void pointer é um ponteiro que pode apontar para qualquer tipo de objeto. Um null pointer é um ponteiro que não aponta para um endereço. Um void pointer pode ser um null pointer.

Referências
https://stackoverflow.com/questions/34842224/when-to-use-const-void
https://www.geeksforgeeks.org/void-pointer-c-cpp/
6.13 — Void pointers