La ragione sta nel solito fatto che ...gli array sono dei puntatori COSTANTI, puoi modificare/inizializzare gli elementi dell'array, ma non l'array stesso, cioè il puntatore rappresentato dall'array. Se tu scrivi:
char *p[] = messaggi;
stai dicendo che l'array p deve puntare all'indirizzo che è puntato da messaggi, e questo non puoi farlo. Se invece fai
char **p = messaggi;
non dà errori proprio perchè p è un puntatore, non un array, e come tale puo essere inizializzato/riassegnato.