12 Beginner The Hundred
The Pointer That Printed Its Contents
the same pointer, printed twice, two different answers
#include <iostream>
int main() {
int count = 7;
const char* label = "widgets";
std::cout << "count is at " << &count << '\n';
std::cout << "label is at " << label << '\n';
std::cout << "label is at " << static_cast<const void*>(label) << '\n';
}
Run it. Which of the three lines print an address?
Answer
Two of them. Typical output (GCC on x86-64; your addresses will differ, and the stack one changes from run to run):
Same pointer on the last two lines; only the cast got an address out of it.
Why¶
operator<< handles pointers with a catch-all const void* overload — any object pointer
converts to it, which is how &count becomes an address. Character pointers never reach
it: std::ostream also has dedicated overloads for const char* (plus the signed and
unsigned char flavours) that treat the pointer as a NUL-terminated string, and an exact
match beats a conversion every time. So label prints its contents, and the only way to
see where it points is to launder it through a cast. The flip side is nastier — stream a
char* whose bytes are not NUL-terminated and the stream reads straight off the end,
undefined behavior that often looks like it worked, because some zero byte usually
turns up soon after. Only narrow character pointers get the text treatment — a char16_t
literal prints as an address under C++17, and C++20 deletes that overload so the line
stops compiling at all.
-Wall -Wextra says nothing about any of this — the compiler assumes you meant it.
The fix¶
Cast when you want the pointer value rather than the text:
std::cout << static_cast<const void*>(label) << '\n'; // 0x402010 — the address
std::cout << label << '\n'; // widgets — the contents
Takeaway: to iostreams a char* is text, never a pointer value — say
static_cast<const void*> when you want the address.
Try it: g++ -std=c++17 main.cpp -o demo && ./demo