In the class ChangeChar, the following needed to be a reference to the class rather than a pointer to a pointer.
void fChangeHealth(MyClass &myChar, int h) { myChar.fAlterHealth(h); }
void fChangeName(MyClass &myChar, string n) { myChar.fAlterName(n); }
You can use either a pointer (no need for pointer to pointer here, likely you have mixed up the level of dereferencing somewhere else that makes you think this), or a reference.
This is obviously not great as working with pointers is a better way round, but for anyone searching I thought it best to illustrate that both pointers and reference are possible outcomes.
Pointers are not "better" than references, nor are references "better" than pointers -- they do different things, with some overlap.
A pointer is simply an address in memory -- it tells you the house-number and street of your data, just like an address in the real world. With a pointer, you can add and subtract from the address to reach the neighbors houses, and you can keep doing so to walk down the street; or, you can write down a new address and end up in a completely different neighborhood. However, if you write down any random address and handed it to a friend, they might end up someplace dangerous, somewhere they're not allowed, or trying to find a place that doesn't exist, so you have to be sure of what you're writing down. A pointer can also be 'null' which is a way of telling everyone who sees the address that its not a real address -- like if you wrote down the real-life address '123 Don't Go Here St."
A reference is also an address in memory, exactly like a pointer except in two critical ways -- first, you cannot re-assign, add, subtract or do anything else to a reference -- in the street-address analogy, you can go to exactly one house, but you can't then go to their neighbors or walk down their block, you can't write down a completely new address either, once you write down an address in a reference its magically transfixed and cannot be undone or changed; second, a reference must always be a valid address and therefore can never be null -- if you have a reference to something, you're guaranteed to find what you expect, you won't be surprised by an empty lot or to find yourself someplace you're not allowed. These two differences, while they make references less flexible than pointers, also make references safer.
Therefore, its actually correct to prefer references to pointers -- whenever a job *can* be done with a reference, it almost certainly *should* be done with a reference -- the only exception to this guidance is that sometimes third-party code that you're using might be written in a way that makes using a pointer more convenient (or necessary), then its sometimes okay to use a pointer even when a reference would do just as well. Otherwise, you should only use pointers when you might need to signal that the pointee is invalid (null), visit the neighbors, or move all around the city.
Finally, returning to the original question of when might you have a dangling pointer and/or memory leak and how do you avoid it, well, you have the potential for a dangling pointer / memory leak whenever you use new -- all it takes is to fail to call delete. But there's lots of ways to fail at calling delete: you might simply forget to type 'delete thing;', or elsewhere in the code you might find that you just forgot about what it was you needed to delete, or you might not hit the code that calls delete like you expect because of a bug or because of conditions you didn't anticipate -- or trickiest of all you might have done all that right, but an exception might have caused your program to skip the line that deletes the thing. Deleting everything you allocate, every time, 100% of the time, no matter what went wrong, is hard. People who have programmed most of their lives can still make these kinds of mistakes.
But good news: there are tools to help you built right into C++! The tools are called unique_ptr and shared_ptr (and shared_ptr's friend, weak_ptr, but that's a story for another time). When you allocate something and store that pointer in a unique_ptr, it always gets deleted the moment you can no longer use that address, no matter what, even if an exception is thrown -- this is super, super useful. But unique_ptr has to be the only one that owns that allocation to do its work, others can look at it, but they all have to agree that only the unique_ptr owns the thing, and will take care of deallocating it, and as a consequence of that, the unique_ptr must stick around longer than anyone else who might want to look at the thing, or the thing won't be there when they come to look at it (like your friend had arrived at the address to find what looks to be an uprooted house, plumbing coming up from the ground still spurting water into the air).
That's where shared_ptr comes in. shared_ptr is a way of saying that several shared pointers share the responsibility of deleting the thing. The way it works is like this: every shared pointer makes a mark on a chalk-board that says they're using the thing, when they're done using the thing they erase their mark. After awhile, there's only one shared_ptr left, and when its done using the thing there are no other marks on the chalk-board, this means he's the shared_ptr that has to delete the thing, and that its safe to do so because everyone else is done with it. Its like they're a basketball team during practice, the last player off the court has to put the ball away.