I think you're mixing up two different concepts. If you have two pointers p and q of any type, then p == q always compares the addresses stored in the pointers rather than the objects being pointed at. As a result, the statement
if (p == q)
tests whether p and q are literally pointing at the same object. As to why you're getting back the same objects - many compilers, as an optimization, will pool together all string literals of the same value into a single string literal and set all pointers to share it. This optimization saves space in the binary. It's also why it's undefined behavior to write to a string literal - if you could write to a string literal, then you might accidentally pollute other strings initialized to that literal.
Independently, the streams library is specifically programmed so that if you try to print out a const char *, it will treat that const char* as a pointer to the start of a null-terminated string, and then print out all of the characters in that string.
If you wanted to instead print out the addresses, you can cast the pointers to void* first:
cout << static_cast<const void*>(p) << endl;
cout << static_cast<const void*>(q) << endl;
The reason this works is that the streams library is designed so that if you try to print out a pointer that isn't a character pointer, it displays the address. The typecast basically tells the compiler "please forget that this is actually a char* and instead treat it like a generic pointer."
Similarly, if you want to compare the strings themselves, use strcmp:
if (strcmp(p, q) == 0) {
// Equal!
}
That said, in C++, you should probably consider using std::string instead of const char*, since it's safer and easier to use.