= Notes on `const` correctness = == Syntax review == ||`const int x;`[[br]]`int const x;`||The value of the `int` cannot be changed.|| ||`const int *p;`[[br]]`int const *p;`||The value of the `int` cannot be changed through this pointer (`*p = n` is disallowed).|| ||`int *const p;`||The pointer cannot be repointed (`p = q` is disallowed).|| ||`const int *const p;`||The pointer cannot be repointed, and the value of the `int` cannot be changed through this pointer.|| ||`const int a[3];`||The values of the `int`s in the array cannot be changed.|| ||`const char **pp;`||The `char` pointed to by `*pp` cannot be changed through it.|| ||`char *const *pp;`||The `char *` pointed to by `pp` cannot be repointed through it.|| ||`char **const pp;`||`pp` cannot be repointed.|| ||`const char *const *pp;`||The `const char *` cannot be repointed through `pp`, and the `char` cannot be changed through `*pp`.|| ||`const char *const *const pp;`||All of the above.|| `foo *` may be implicitly converted to `const foo *`, but not the other way around. `foo **` may ''not'' be converted to `const foo **`. (Otherwise, you could write through `const foo *p` as follows: `foo *q; const foo **pq = &q; *pq = p; *q = …;`) However, it is safe to convert `foo **` to `const foo *const *`. C++ lets you do this implicitly (conv.qual 4 in the standard); for no particular reason, C does not. In C, `void *` may be implicitly converted to and from `foo *`, and hence also to `const foo *`. `const void *` may be implicitly converted to and from `const foo *`, and hence also from `foo *`. == How `const` relates to `malloc` and `free` == Note the prototypes of `malloc` and `free`: `void *malloc(size_t size);`[[BR]] `void free(void *ptr);` This implies that a `foo` cannot be freed through a `const foo *`. Therefore, the code that “owns” (i.e., is responsible for allocating and freeing) the `foo` must hold on to the (non-`const`) `foo *`. When possible, it should pass only a `const foo *` to any other code that does not need to modify or free the `foo`. Do not try to subvert this rule by adding casts! Code that needs to free a `foo` should not have been given a `const foo *`. A cast only hides this potential bug. `gcc -Wcast-qual` will warn you about casts that throw away `const` qualifiers. These rules can help you locally find memory leaks and double-free bugs. For example, if a `foo` is malloc’d and only stored into a `const foo *`, you know that it has been leaked. If you ignore a compiler warning that `const foo *` is converted into `foo *`, you may be freeing a `foo` that was not supposed to be freed. == `const` and strings == For historical reasons, literal strings have type `char[]` by default. However, literal strings are still put into a read-only section of the program image, and it is invalid to modify or free one. Therefore literal strings should always be stored in a `const char *`, never in a `char *`. If you compile with `gcc -Wwrite-strings`, literal strings will be typed `const char[]` like they should be, to prevent you from making the mistake of storing one in a `char *`. == Using `const` effectively == If C had been designed with perfect foresight, `const` would have been the ''default'' on all types, and a qualifier would have been required to allow a value to be modified or freed. But, we do not live in a perfect world, and writing `const` absolutely everywhere would be a waste of typing and make your code harder to read. It is usually not useful to qualify something that is not the target of a pointer type, such as a simple local variable (`const int n;`), or a function parameter or return type (`const int fib(const int n);`). That would add no safety because any modifications to the parameter of `int fib(int n)` are not visible to the caller, and the return value cannot be modified in place anyway. However, you should always make sure that the target of a pointer type is correctly `const`-qualified. Think carefully about whether to use `const foo **p` and/or `foo *const *p` (but don’t worry about `foo **const p`).