In the definition of const int *ptr = &i; essentially says: "I will not change i through ptr ." He does not say that int , which ptr points to const , he says that ptr should not be used to change it.
This conversion is allowed because it makes sense: since i not const , I can allow it to be changed, but I can also not change it. No rule is interrupted if I do not want to change i . And, if I create a pointer to i and say: “I will not use this pointer to change i ”, that’s good too.
The reason you want to do this is to pass the address of the object to a routine that takes a pointer to a const object. For example, consider the strlen procedure. The strlen routine does not change 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. Therefore, I call strlen . Now I pass a pointer to char as an argument to the parameter, which is a pointer to const char . We want this transformation to work. This makes sense: I can change my char if I want, but the strlen routine is not suitable, so it treats them as const char .
1) You get an error message with *ptr = something; because you declared ptr as a pointer to const int , but then you broke your promise not to use ptr to change int . The fact that ptr points to an object that is not const does not cancel your promise not to use ptr to change it.
2) It is incorrect to assign the address of a const object to a pointer to const . The destination does not say that the object is const , it says that the pointer should not be used to modify the object.
Also, although you did not ask this, the const attribute in C is not completely required. If you define an object as const , you should not modify it. However, there are other situations in which a pointer to const is passed into a subroutine that converts it to a pointer to const . This is actually a defect in the language, the inability to save all the information necessary for processing const ways that we might prefer. An example is the strchr routine. Its declaration is char *strchr(const char *s, int c) . The s parameter is equal to const char * , because strchr does not change its input. However, the pointer that the strchr routines strchr is inferred from s (it points to one of the characters in the string). So, inside strchr converted a const char * to char * .
This allows you to write code that goes from char * to strchr , and uses the return pointer to change the string, which is good. But this means that the compiler cannot completely protect you from errors, such as passing const char * to strchr and using the return pointer to try to change the string, which may be an error. This is a flaw in C.