const MatrixYou've seen const char *src in a function signature. Now learn the whole picture β three declarations, two questions, and you'll never be confused again.
const lock the door?In lesson 2's model solution, you wrote:
void mystrcat(char *dest, const char *src) { ... }
The const next to src tells the compiler: "I promise not to modify the characters src points at." That's useful β it lets you pass string literals without warnings, and it catches accidental writes to the source.
But C lets you put const in three different places around a pointer declaration, and each one locks a different door. This is one of the most confusing pieces of C syntax β but it resolves to two questions you can always ask.
const as "constant." Read * as "pointer to." Move right-to-left. Whatever const is closest to, that's what it locks.
Let's read all three forms aloud:
| Declaration | Read aloud (rightβleft) | What's locked? |
|---|---|---|
const char *p; |
p is a pointer to a char that is constant | The data β *p is read-only. p itself can change. |
char * const p; |
p is a constant pointer to a char | The pointer β p can't point elsewhere. *p can change. |
const char * const p; |
p is a constant pointer to a char that is constant | Both β locked down entirely. |
That's the whole table. Three declarations, no more.
const char *p β "don't touch the data"const char *p = "Hello";
p = "World"; // β pointer can change β now points at "World"
p[0] = 'J'; // β compile error: read-only location
This is the one you used in mystrcat(dest, const char *src). The function promises: "I'll read src's characters, but I won't change them." The caller can pass literals, arrays, anything β without fear.
char const *p is the same thing
const char *p and char const *p are identical to the compiler. Both mean "pointer to constant char." The C standard allows both orderings. Pick one and stick with it β most C code uses const char * (const-first). But if you see char const * in someone else's code, now you know it's the same.
char * const p β "don't move the pointer"char buf[] = "Hello";
char * const p = buf;
p = buf + 1; // β compile error: cannot assign to 'p' (it's const)
p[0] = 'J'; // β the data itself is writable
This locks the arrow, not the target. The pointer is nailed in place β it will always point at buf β but you can freely modify the characters through it. Less common in function signatures, but you'll see it in loops where you want a fixed starting point.
const char * const p β "don't touch anything"const char * const p = "Hello";
p = "World"; // β cannot change pointer
p[0] = 'J'; // β cannot change data
Total lockdown. Used for things like configuration strings that should never change and never be redirected. Rare, but unambiguous when you see it.
const near a pointer, ask:
*p?)
const is before the * β answer (2) is no.
const is after the * β answer (1) is no.
const is in both places β both answers are no.
const char *p β data locked, pointer freechar * const p β pointer locked, data freeconst char * const p β both locked
Look at your concatenate_own_func.c:
char *q = str2; // q reads from str2
while (*q != '\0') {
*p = *q; // reads *q, writes *p
p++;
q++;
}
q only reads. It never writes through *q. So in a function version, src should be const char * β it tells the compiler (and anyone reading your code) that this pointer is input-only.
By contrast, p writes into dest. So dest must not be const β the whole point is to modify it.
void mystrcat(char *dest, const char *src);
^^^^^^^^ writable ^^^^^^^^^^^^ read-only
This is the standard C convention for any function that transforms data: input is const, output is not. You'll see it in every library function signature β strcpy(char *dst, const char *src), strstr(const char *hay, const char *needle), etc.
const earns its keepconst in function signatures is primarily a documentation tool. It tells callers "this function won't modify your data." But it's documentation the compiler enforces:
void process(const char *s) {
s[0] = 'X'; // compiler error β caught before it becomes a bug
}
Without const, that line compiles fine β and silently corrupts the caller's data. With const, the compiler stops you. It's a seatbelt, not a handbrake.
const. If you find yourself passing char * when you only read, change it to const char *. It catches bugs and communicates intent. There is no downside.
For each declaration, answer: can you reassign the pointer? and can you write through *p? Then open the answer.
const int *x;*x? No. const is before the * β data is locked, pointer is free. This is the "pointer to a constant int" β same pattern as const char *.
int * const x = &n;*x? Yes. const is after the * β pointer is locked, data is free. x will always point at n, but you can change n's value through *x.
char *p = "hello"; p[0] = 'H'; β what happens?"hello" lives in read-only memory. Writing through p is a runtime violation. The compiler might not catch it (because p is declared as char *, not const char *). p as const char *p = "hello"; and now the compiler will catch the p[0] = 'H' at compile time. This is why const matters β it turns silent UB into a visible error.
const form goes in a function parameter for read-only input?const type * β the "pointer to constant data" form. The function receives a pointer it can advance, but the data behind it is locked. Example: size_t mystrlen(const char *s); β mystrlen walks s forward reading characters, but never writes any.
const to your own functionsOpen your concatenate_own_func.c (or any file with mystrlen, mystrcat, etc.) and:
void mystrcat(char *dest, const char *src)mystrlen too: size_t mystrlen(const char *s) β notice the input is constsrc[0] = 'X'; inside mystrcat. Compile. What happens?dest to const char *dest. What breaks, and why?The goal: feel the compiler push back when const is violated, so the rule becomes muscle memory, not theory.
const pointer declaration and immediately know what's locked and what's free β using the two-question test. You know that const char * and char const * are the same thing. And you know to use const on input-only function parameters as a compiler-enforced seatbelt.
const and malloc?", "why can I pass char[] to a const char * parameter?", "does const affect performance?" β type it and we'll dig in.
const qualifier