The first one needs to be const char, as you cannot actually modify the C-strings.
The second one doesn't assign b to be the address of some constant 3, instead it assigns b to point to the memory address 0x3, which you probably don't have access to.
What happens is that you declare an array of two pointers to const char.
The two pointers, namely a[0] and a[1] will point to the string literals "hello" and "world" respectively.
It is important to remember that a[0] and a[1] are not arrays. They are pointers. And the arrays they point to cannot be changed, hence the const was added for correctness.
The second case shouldn't compile without a cast in C++ (the C language is more permissive).
int *b = reinterpret_cast<int *> (3);
Even so, it is not a good idea to give the pointer values yourself.