Righe come queste

ret[elem -1] = (char *)malloc(strlen(tmp) * sizeof(char));
ret[elem -1] = tmp;

non hanno senso. Assegni due valori diversi uno dopo l'altro allo stesso elemento, creando un memory leak ...

Fossi in te rivedrei tutto l'algoritmo che stai usando, anche perché non si riesce a capire molto.

E farei degli esercizi molto più semplici con puntatori, stringhe e caratteri perché devi chiarirti melgio il loro utilizzo.