Certo che si può allocare dinamicamente. Per allocare un char *matrice[c][r] devi:

codice:
matrice = (char ***) malloc (c*r*sizeof (char *));
Se cambia c o r devi riallocare l'intera struttura (perché deve essere contigua per definizione):

codice:
matrice  = (char ***) realloc (matrice, c*r*sizeof(char *));
Però ho dei seri dubbi che il tuo scanf("%s", mat[i][0]) sia sano: quanto sopra alloca lo spazio per la matrice, non per le eventuali stringhe a cui punta ogni elemento della matrice.