Semantically the first example means "a pointer to a const int" not "a const pointer to an int".
So, when you set i to point to j (a non-const int). i now points to a const, as such you can't change the value of j through the pointer i, for example:
int main()
{
const int *i;
int j=2;
i=&j;
*i = 4;
}
Won't compile, giving the error "assignment of read-only location ‘*i’". So the pointer restricts your access to the value being pointed to. But the pointer itself can still be changed.
C being the language that it is, doesn't really offer much protection and you can often throw away the const and assign the variable a new value anyway e.g.:
#include <stdio.h>
void assign(int *a) {
*a=5;
}
int main()
{
int const i=1;
int j=2;
assign((int *) &i);
printf("i: %d\n",i);
}
But I'm not sure I'd recommend it. And while this works in some versions of gcc, this behavior is likely undefined in the C standard.