Skip to content

31 Intermediate The Hundred

Two Consts, Two Meanings

same keyword, two different locks

#include <iostream>

int main() {
    char greeting[] = "hello";
    char farewell[] = "goodbye";

    const char* p = greeting;   // two pointers, two consts...
    char* const q = greeting;   // ...so both are locked down, right?

    p = farewell;
    q[0] = 'H';
    p[0] = 'J';
    q = farewell;

    std::cout << "p -> " << p << '\n';
    std::cout << "q -> " << q << '\n';
}

Which two of those four assignments does the compiler reject?

Answer

Not the ones you'd guess. p = farewell; and q[0] = 'H'; are both fine — the program prints p -> goodbye and q -> Hello. The rejected pair is p[0] = 'J'; and q = farewell;.

Why

Read the declaration right to left. const char* p is "p is a pointer to a char that is const", so the characters are protected and the pointer is free to roam. char* const q is "q is a const pointer to a char" — the pointer is frozen, while the characters it names are fair game. GCC 11 says exactly that, one word apart:

main.cpp:13:10: error: assignment of read-only location ‘* p’
   13 |     p[0] = 'J';
main.cpp:14:7: error: assignment of read-only variable ‘q’
   14 |     q = farewell;

"Location" is the thing pointed at; "variable" is the pointer itself. The same asymmetry is why char* s = "hi"; earns ISO C++ forbids converting a string constant to char* (-Wwrite-strings, on by default) — a literal's characters are const, so only the first form may point at one.

The fix

Spell out which half you meant — and note that const char* and char const* are the identical type, so the second spelling makes the right-to-left reading literal:

const char* p = buf;         // pointer to const char: repoint yes, write no
char* const q = buf;         // const pointer to char: repoint no,  write yes
const char* const r = buf;   // both frozen: repoint no, write no

Takeaway: const applies to whatever is immediately to its left — unless it is leftmost, in which case it applies to what is on its right.

Try it: g++ -std=c++17 main.cpp -o demo && ./demo — add -DSHOW_BUG to meet the two errors.

Open in Compiler Explorer ↗ Open SHOW_BUG variant ↗ Quiz this entry