While I use *ptr, I can change the const data *a. Why?
Because your program is causing undefined behavior. You lied to the compiler that b is non-const by casting const-ness away from the pointer produced by &b, but writing to that pointer on the *c = 200 line is undefined behavior.
Both the address of b and *c are the same, but the data are different. Why?
It happens for the same reason: the behavior is undefined.
As for the real-life scenario when this would happen, I would speculate that the compiler has optimized out the read of b, because you promised it that b is const. However, the compiler found a clever way of getting back at you by replacing a read of the actual b with the output of a constant that has been assigned to b originally.