In the case where p="hello world"; (1st case at the time of this edit), p is being initialized to point to a read-only memory region which contains the string "hello world" (string literal).  This read-only memory region is created at compile time.
In the case that causes the segmentation fault (2nd case at the time of this edit), p is uninitialized and copying anything to it will produce unpredictable results because the location in memory that p is pointing to is not specified by the code.
Before you can copy a string to p, you must specify the memory that p is pointing to.  
You can allocate this memory on the stack 
char buf[BUFSIZ] = ""; /* local variable */
on the heap
char *buf = malloc(BUFSIZ); /* don't forget to free */
or in the __DATA segment.
static char buf[BUFSIZ] = ""; /* global variable */
You can then initialize p to point at the memory buffer.
char *p = buf;
This is similar in concept to initializing p to point to the string literal in read-only memory.  Unlike the case where p points to the string literal, you can now copy a string to the character pointer as it does not point to read-only memory.
Note: I intentionally created a separate buffer and initialized p to point to it to help make my point.