Pointers are one of the big differences between Java and C++. I went from C/C++ to Java, so I never had to go through that.
First, on your original question #2, you are essentially correct, but when you are deleting an array, you need to use the array delete:
Otherwise, as I understand, the entire array would not be freed up and you'd have a memory leak.
char * c = new char;
delete  c;
As for trying to map out the heap, there are low-level ways of doing it; try looking for a program called HeapWalk and see if you can get the source code for it.
I don't know whether the new standard defines how the heap is to be maintained, but I don't think that it does. So what you figure out on one system with one compiler might not work with another.
Now, as for copying pointers. There is a big difference between copying a string and pointing to a string, as you appear to be aware. This difference can cause some unexpected problems.
It's easier to describe with code:
If you assign a pointer to a pointer, all you are doing is setting them to point to the exact same location in memory. If one of the pointers deletes that location, then all the other pointers pointing to the same location will all be invalid.
char * s = "Hello World!"; // points to a string in non-heap memory
char * c2 = NULL; // doesn't point to anything
char * c3 = NULL; // doesn't point to anything
c = new char[strlen(s)+1]; // points to a block in heap
c2 = c; // points to the same location as c does
c3 = new char[strlen(c)+1]; // points to a block in heap
delete  c;
cout << c2 << endl; // ERROR! c2 no longer points to valid data!
cout << c3 << endl; // Works! c3 kept its own copy of the string,
// and so is unaffected by c having gone away.
The lesson here is that in C and in C++ all variables declared within a code block automatically cease to exist when you exit that code block. A code block is defined as a collection of statements placed between braces, like the body of a function. If you want to make a value declared with a code block to be available after exiting that code block, then you need to copy it to a variable outside the code block.
I'm not sure what you are trying to do with your isPointerOnHeap function. If you just want to ensure that you don't delete a non-heap pointer, then there is a far easier and better way. If you new something, it is being created on the heap. So all you need to do is to delete everything that you new and only that. One piece of advice I recently read is that as soon as you write the new statement, also write its delete statement so you don't forget. My particular practice is, upon creating a class, I immediately write the default constructor with the default initializations and the destructor with the deletes for the dynamically allocated properties. Then when I add a new property to the class, I immediately add it to the destructor if applicable and then I add it to the constructors.
However, if you really do want to play with the heap, then there should/could by compiler-specific constants and functions available. MS Visual C++ has such; just look in the help file under "heap constants".