char *strarray[5];
will allocate array of five pointers to the characters (which can be interpreted as strings).
What this will not allocate is the memory space to place these five strings to. So, if you want to make all pointers to point to the different strings, you need to allocate them yourself.
However, as these are pointers, you don't really need to allocate anything, if you don't want to. That is why your first example is working. strarray[0]="hello";
will make the first element of the array to point to the location where "hello"
string literal is stored (the compiler will put this literal somewhere in the memory for you, so your pointer will point to the valid memory location).
To sum up, in the first example, your pointer is pointing to the memory already allocated and initialized with "hello"
(compiler did this for you) - you're not copying the string, you're just assigning value to the pointer. In the second example your pointer is pointing to some undefined location, which you didn't explicitly reserved, but you're trying to write into it.