Scrivere:
codice:
bool Menu (Client* clients[], int &i)
o
codice:
bool Menu (Client** clients, int &i)
per il compilatore è la stessa cosa. La prima forma è scarsamente usata se non nelle prime fasi di sudio del linguaggio, anche se rende meglio l'idea che la funzione deve riceve un array e non un banale puntatore.

Adesso se avessi avuto una funzione "InsertClient" di questo tipo:
codice:
void InsertClient (Client* client[], int &i)
nella funzione Menu, non avrei dovuto utilizzare & per l'indirizzo. Perchè?
Se stai parlando di questa riga:
codice:
InsertClient(&clients[i], i);
il compilatore si lamenta.
Se parli di questa:
codice:
while (Menu(clients, i)); // loop per il menu
Un array decade in un puntatore con lo stesso nome dell'array.
E' come aver scritto:
codice:
while (Menu(&clients[0], i)); // loop per il menu
e poi teoricamente nel main io dichiaro l'array di puntatori a clients con una dimensione di 100.
Perchè quando vado a riempire l'array, ho bisogno di allocare memoria dinamicamente con new?
Dopo che io ho già dichiarato la dimensione dell'array?
Hai detto al compilatore di riservarti 100 locazioni per i Client*, ma ognuna di queste locazioni non punta a nessun Client. L'allocazione col new serve a quello.