20

The use of const with a pointer can make the pointee not modifiable by dereferencing it using the pointer in question. But why neither can I modify what the pointer is not directly pointing to?

For example:

int a = 3; const int* ptr = &a; *ptr = 5; 

will not compile. But why does

*(ptr + 2) = 5; 

also not compile? I'm not changing what the pointer is pointing to.
So do we have to say that using const with a pointer in such a way not only makes not modifiable what the pointer is pointing to (by dereferencing the pointer) but also anything else, to which the adress we get using the pointer?

I know that in the example I'm trying to access not allocated memory, but this is just for the sake of discussion.

1
  • So did you expect the compiler to assume that only the first sizeof(int) bytes are const? It makes more sense that the compiler will assume that any memory address accessed with ptr is a read-only address ("physically" read-only, or at least read-only in the "perspective" of the function which uses ptr). Commented Dec 21, 2014 at 11:35

5 Answers 5

25

ptr +2 simply has the same type as ptr namely is a pointer to a const object.

Pointer arithmetic supposes that the object that is pointed to is an array of all the same base type. This type includes the const qualification.

Sign up to request clarification or add additional context in comments.

3 Comments

So it's just like int + float = float, so const [type]* + some value = const [type]*, right?
@Root149, something similar, yes. Adding any integer type to a pointer type gives back the same pointer type.
Only with pointers types decay (everything gets flattened to pointers when pointers are involved, including arrays), where normal integer types get promoted up to a type that can represent everything.
13

The non-modifiability introduced by const depends on where const is written.

If you write

const int * ptr = &a; 

(or int const * ptr = &a;), the const refers to the pointee, so using the pointer for writing to the destination is forbidden.

(OTOH, if wou wrote

int * const ptr = &a; 

you couldn't modify ptr.)

In your case, everything involving writing to the destination is forbidden.

This includes *ptr and ptr[0] (which are equivalent), but also everything involving a modification of the destination address, such as *(ptr + 2) or ptr[2].

3 Comments

(and note that const int * and int const * are the same thing - pointer to const, not const pointer.)
also note that given "int * const ptr = &a;", you can write "*ptr = 5;" but not "++ptr". Good coverage of the rules is in the answer at stackoverflow.com/questions/1143262/… - the first line of the answer - "Read it backwards" - sums it up beautifully.
@frasnian This is essentially what I said - ++ptr is covered by "you cannot modify ptr".
9

Although other answers explain the technicalities of why it doesn't work, I'd like to offer a more general reason: it's the only thing that makes sense.

The problem is that there is no general way for the compiler to decide whether p + something is the same as p or not, because something can be arbitrarily complex. A rule like "Values pointed to by p and p + 0 are unmodifiable, but other values can still be modified" cannot be checked at compile time: imagine if you wrote:

*(p + very complex expression) = ... 

should your compiler be able to figure out if very complex expression is zero? What about

int s; scanf("%d", &s); *(p + s) = ... 

What should the compiler do in that case?

The only reasonable choice here was to make any value accessed through p unmodifiable.

2 Comments

This behaviour is not caused by any ambiguity in compiler decision making. It is a simple and correct consequence of the rules of the type system.
@JamesT.Huggett: I'm not sure what you mean by "ambiguity in the compiler decision making"; it's true that the behaviour is a consequence of a typing rule, and my answer just attempts to explain why the rules of the type system were designed this way.
4

Since a pointer can also be used as an array (think about argv), the compiler restricts each access in which the pointer is involved. This way the whole array is read-only.

3 Comments

Well, argv is just a pointer, since writing char* argv[] is equivalent to char** argv. we just create the illusion of an array.
@Root149 Array or not makes no difference when it comes to accessing it, as access works via pointers anyway.
@Root149: Right. And because of that illusion, the compiler doesn't know if your pointer is also such an 'illusion'. It may be used as an array, like argv, and therefore every write-access to it must be restricted (no matter if its ptr[0] or ptr[100]).
3

Let's think about the type of the expressions.

const int* ptr = &a; 

The type of ptr is const int*.

So the type of *ptr is const int. Not modifiable.

The type of (ptr + 2) is still const int* so the type of *(ptr + 2) is const int which is again not modifiable.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.