The sizeof operator takes an expression or a parenthesized type as its argument. It does not evaluate its argument unless that argument is a variable length array. Either way, the size is determined from the type of the operand.
So, given a pointer int *p, sizeof *p yields the size of an int since the expression *p has type int. There is no evaluation and hence no dereference here. Alternatively, you could use sizeof(int) to find the size of an int. In the first case the operand is the expression *p, and in the second case the operand is the parenthesized type (int).
It may be worth commenting that struct x *ptr = malloc(sizeof(*ptr)); is a useful C idiom. The parentheses around *ptr are not needed since *ptr is an expression, not a type:
struct x *ptr = malloc(sizeof *ptr);
This construct is clear and easy to maintain when types change, e.g., when struct x is no longer desired, but now struct y is needed, there is only one thing to change:
struct y *ptr = malloc(sizeof *ptr);
After this one simple change ptr is a pointer to struct y, and the correct amount of memory has been allocated for one struct y.