Intanto ringrazio te e tutti gli altri che mi hanno risposto (anche per i pezzi di codice, utilissimi ), perché mi state aiutando a chiarire un po' le idee (che, per quanto riguarda i puntatori, non sono mai abbastanza chiare) e soprattutto a proseguire col programma...

Ho usato un void** perché ho ripreso le indicazioni del prof. che nelle slide mostra una struttura definita così (che in effetti usa una pila con riferimento al prossimo elemento e non un array):
codice:
struct struct_pila {
 void** elements; // contiene gli elementi della pila 
int next; // indice dove inserire il prossimo elemento
int capacity; // lunghezza dell’array elements 
};
Anche se cercando qui e là ricordo di aver letto una persona che diceva ad un'altra "non è il caso di dichiararlo void**, basta void* per fare un array di generici, altrimenti crei un array di array"

Ho un'altra domanda, sempre relativa a tutto ciò (penso l'ultima ):
vorrei creare un metodo toString() che crei una stringa con l'elenco degli elementi contenuti nell'array. Siccome void* necessita un cast, ma io non so se l'utente metterà un char o un int/long/..., dite che c'è modo di farlo? Utilizzando un metodo solo e senza passare come argomento una variabile che identifichi il tipo.
Per rispiegare meglio:
- L'utente nell'array inserisce degli interi, chiama il toString(array) (senza specificare con altri parametri cosa contiene l'array) e stampa la stringa ottenuta.
- L'utente crea un array in cui inserisce dei char e sempre col toString(array) ottiene un'altra stringa.

Cercando su google ho trovato che non è possibile farlo in quanto non c'è una funzione che "dica" di che tipo è il void che utilizzo...
E allora mi chiedevo il consiglio del professore "Stampate il valore del puntatore (piu' meno la stessa cosa che fa la toString() di Object in Java)." come fa a creare la stringa giusta