Visto che mi hai anticipato, ti spiego il perché succede.
Intanto...
Non posso cambiare i parametri perchè devo seguire il testo della traccia.
Che immagino imponga l'uso di char* al posto di std::string, giusto?

In il problema si divide in due parti:
la prima (che hai risolto) era un tuo errore, la seconda è un comportamento del C++ ai limiti della "undefined behaviour" (comportamento indefinito).
codice:
// in crea_animale()
...

	do{
		cin >> a_opt;
		if(a_opt==0){
//			Cane c(name, age, gender, breed); 
			ptr = new Cane(name, age, gender, breed); 
			cout << "elemento creato:";
//			c.stampa(); 
                        ptr->stampa();
			r.tipo="Cane";
//			Cane* c_ptr=&c; 
//			ptr=c_ptr; 
                       < * > 
                 }else if(a_opt==1){
// eccetera
Osserva lo scope di c nelle righe rosse. E' interno all'if. Questo vuol dire che nel punto indicato in blu, c, con annessi e connessi, non esisterà più. Questo lascia ptr in un limbo: da un lato sa a cosa puntare (ha la dichiarazione di una classe di tipo Animale), dall'altro l'oggetto a cui dovrebbe puntare non esiste più insieme alla sua vtable.
Qui entra in gioco il comportamento "strano" (forse voluto visto che si parla di un linguaggio ad alta efficenza) del C++.

E' possibile infatti (per quanto possa sembrare assurdo) richiamare una funzione membro, da un puntatore a una classe, senza avere l'istanza della classe! Purchè il puntatore stesso non sia nullo e la funzione membro non acceda a dati interni della classe. Detto in soldoni:
codice:
struct Foo {
	void test() {
		cout << "ciao" << endl;
	}
};

int main(int argc, char* argv[] ) {

	Foo* f;
	f->test();
}
funziona! (Testato con VC++ 2010 in release mode, in debug lancia un giusto run time check error).

Pertanto l'errore di "chiamata a funzione virtuale pura" è dovuto al fatto che stai usando un puntatore "sporco" di classe Animale, ma non avendo più nessun riferimento in vtable a una funzione get_razza() ridefinita in una classe derivata, il compilatore è costretto a chiamare quel che trova; vale a dire la funzione virtuale pura.

Ci sono poi altri errorini: per esempio usare char* name="" (è un puntatore, sebbene ci si voglia illudere che sia una stringa C. E il valore di default per i puntatori è NULL e basta.
Poi:
codice:
void stampa_dati(char* name1, const int n_record){
	ifstream f;
	Record vet[n_record];
	f.open(name1, ios::in);
(DEVC++ o derivati si sgama subito.)
NON puoi dichiarare un array in quel modo, usando una variabile il cui valore è noto a run time.
Il fatto che sia const non significa niente.
Se ti serve un array di Record la cui dimensione puoi conoscerla solo a run time, allocala nell'heap con new.

Ultima cosa:
quando chiede la motivazione e inserisco una stringa, a me va in loop. ma non ho controllato a fondo il perché.