1. Gli array monodimensionali vengono passati come puntatori al primo elemento, per cui il compilatore sa che per accedere all'n-esimo elemento deve andare a guardare n elementi dopo il primo; nel caso degli array multidimensionali la questione è più complicata, visto che, per accedere all'elemento m,n il compilatore deve identificare l'inizio della riga m, e poi aggiungere n per raggiungere l'elemento desiderato. Il punto è che per raggiungere l'inizio della riga m è necessario conoscere la lunghezza di ciascuna riga, in maniera da saltare avanti, rispetto al primo elemento, di m*lunghezzariga elementi. Un discorso analogo vale per gli array a più dimensioni. È per questo, quindi, che si può omettere solo la prima dimensione: perché le altre servono per calcolare la posizione della riga dell'elemento.
2. Di sicuro non puoi restituire un array non dimensionato (come farebbe il chiamante a sapere quanto è grande effettivamente e quindi a recuperarlo dallo stack dopo la chiamata a funzione?). Non ricordo se si possa restituire un array dimensionato, ma comunque in questo caso non sussisterebbero problemi tecnici.