IMHO, this code is poorly written (that's a polite version of saying "it sucks"). Since the author is already using C++, he should use string for the name instead of char*. Then he wouldn't have to worry about deleting it. The code would produce an error if I do
Code:
{ // any block, maybe of an if
Animal *****;  // should not, but could be
} // error here
This is because he doesn't check for NULL when deleting name in the destructor. Just as bad is that he uses delete instead of delete[] on an array of chars (C-string). Not only that, but he KNOWS that at least at times the memory is allocated using malloc. (strdup uses malloc), which you shouldn't mix with new/delete. Also, he doesn't forward the parameter to the cat/dog constructor to the animal constructor.

Pointers2Pointers:
Since a pointer is also only a variable, you can have pointers pointing to them. And you can have an array of pointers. The author wants a lot of Cats and Dogs so he stores them in an array. But there is not always the maximum number of animals so in order to save space he decides to allocate them dynamically. This means he can't store it in objects but has to use pointers. You have an array of pointers.
char* ptrarr[SIZE];
But the author doesn't know the size of the array at compile time, so he allocates it dynamically too. He needs a pointer to hold the result of new.
char * * ptrarr;
You have a pointer to an array of pointers.