4

Your answers are very much sought to clear this major lacuna in my understanding about const that I realized today.

In my program I have used the statement const int *ptr=&i; but haven't used any const qualifier for the variable i.Two things are confusing me:

1) When I try to modify the value of i using ptr ,where I have used const int *ptr=&i;,I get the error assignment of read-only location '*ptr'|,even though I haven't declared the variable i with the const qualifier.So what exactly the statement const int *ptr=&i; mean and how does it differ from int * const ptr=&i;?

I had it drilled into my head that const int *ptr=&i; means that the pointer stores the address of a constant,while int * const ptr=&i; means the pointer is itself constant and can't change.But today one user told me in discussion(LINK) that const int *ptr means the memory pointed to must be treated as nonmodifiable _through this pointer_.I find this something new as this kinda means "some select pointer can't alter the value(while others can)".I wasn't aware of such selective declarations!!But a 180k veteran attested to it that that user is correct!!.So can you state this in a clearer,more detailed and more rigorous way?What exactly does ``const int *ptr=&i; mean?

2) I was also told that we can lie to the program in the statement const int *ptr=&i; by assigning the address of a non-constant to the pointer.What does it mean?Why are we allowed to do that?Why don't we get a warning if we assign the address of a non-constant to the pointer ptr which expects address of a constant?And if it is so forgiving about being assigned address of non-constant,why it throws an error when we try to change the value of that non-constant,which is a reasonable thing to do,the pointed variable being a non-constant?

#include <stdio.h>

int main ()
{
 int i=8;
 const int *ptr=&i;
 *ptr=9;
 printf("%d",*ptr);
}

error: assignment of read-only location '*ptr'|

Community
  • 1
  • 1
Rüppell's Vulture
  • 3,583
  • 7
  • 35
  • 49

2 Answers2

6

The definition const int *ptr = &i; essentially says “I will not modify i through ptr.” It does not say that the int that ptr points to is const, it says that ptr should not be used to modify it.

This conversion is allowed because it makes sense: Since i is not const, I am allowed to modify it, but I can also choose not to modify it. No rule is broken when I choose not to modify i. And, if I create a pointer to i and say “I am not going to use this pointer to modify i”, that is fine too.

The reason you would want to do this is so that you can pass the address of an object to a routine that takes a pointer to a const object. For example, consider the strlen routine. The strlen routine does not modify its input, so its parameter is a pointer to const char. Now, I have a pointer to char, and I want to know its length. So I call strlen. Now I am passing a pointer to char as an argument for a parameter that is pointer to const char. We want that conversion to work. It makes complete sense: I can modify my char if I want, but the strlen routine is not going to, so it treats them as const char.

1) You get an error with *ptr = something; because you declared ptr as a pointer to const int, but then you violated your promise not to use ptr to modify the int. The fact that ptr points to an object that is not const does not negate your promise not to use ptr to modify it.

2) It is not a lie to assign the address of a non-const object to a pointer to const. The assignment does not say that the object is const, it says that the pointer should not be used to modify the object.

Additionally, although you have not asked this, the const attribute in C is not completely binding. If you define an object to be const, you should not modify it. However, there are other situations in which a pointer to const is passed to a routine that converts it to a pointer to non-const. This is effectively a defect in the language, an inability to retain all the information necessary to handle const in the ways we might prefer. An example is the strchr routine. Its declaration is char *strchr(const char *s, int c). The parameter s is const char * because strchr does not change its input. However, the pointer that strchr routines is derived from s (it points to one of the characters in the string). So, internally, strchr has converted a const char * to char *.

This allows you to write code that passes a char * to strchr and uses the returned pointer to modify the string, which is fine. But it means the compiler cannot completely protect you from mistakes such as passing a const char * to strchr and using the returned pointer to try to modify the string, which may be an error. This is a shortcoming in C.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • Thanks for the answer.I had given up on this question!! – Rüppell's Vulture May 14 '13 at 14:00
  • While C could have provided more useful semantics for "const" [e.g. say that if a parameter is qualified `const return`, then the return value should be treated as `const` when passed a const argument, and as non-const when passed a non-const argument--which would have been ideal semantics for `strchr`] there are many scenarios involving copy-on-write objects where const correctness cannot be statically proven, and a language must either disallow useful semantics or allow constructs whose correctness cannot be verified statically. – supercat Oct 12 '16 at 23:06
-1

Unravelling this:

const int *ptr means that "*ptr is a const int"; i.e. "ptr is a pointer to a const int". You can't write *ptr = 9 since *ptr is a constant. You can however write int j; ptr = &j; since you can allow the pointer ptr to point at a different int.

int * const ptr means "ptr is a constant pointer to an int". You can write *ptr = 9 since you are not changing the address that ptr is pointing to. You can't assign it to something else though; i.e. int j; ptr = &j; will not compile.

As for the second part (2), it's very useful to have const int* ptr, especially in function prototypes since it tells the caller of the function that the variable to which ptr is pointing will not be modified by the function. As for assignment, if you had int* m = &i, then ptr = m is ok but m = ptr is not ok since the latter will 'cast away the constness'; i.e. you've circumvented the const.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483