Il motivo per cui crasha forse ti è più chiaro se "spezzi" la dichiarazione e inizializzazione su 2 righe:
int *p;
p = 2;
In pratica crei una variabile di tipo "puntatore ad intero" ed assegni a tale variabile il valore 2. Cioè stai dicendo che gli indirizzi di memoria da 0x2 a 0x5 (ovvero 4 byte) conterranno 32 bit che saranno da interpretare come un numero intero. Questo è estremamente diverso dal dire "creami un puntatore ad una cella di memoria che contiene il numero 2", cosa che avresti dovuto scrivere come:
int *p;
(*p) = 2;
Di conseguenza se vuoi accedere (leggere o modificare) al valore puntato da un puntatore devi usare l'operatore di dereferenziazione, ovvero l'asterisco.