They either exactly match by definition, or almost the same, depending on the version of C version you're dealing with.
In ISO C99 and C11 we have the following wording (quoting N1570 draft C11) in 6.5.3.2:
The unary operator & gives the address of its operand. If the operand is of type type, the result is of type pointer to type. If the operand is the result of the unary operator * , neither that of the operator or operator & , and the result will be as if both were omitted, except that the restrictions on the operators are still applied, and the result is not a value of l.
So, given:
int *x = ; int *y;
these two are exactly equivalent, even if x is a null pointer:
y = x; y = &*x;
Without the rule of a special case, the behavior will be undefined, since the behavior of the * operator is determined only if its operand is a valid non-empty pointer. But since * never evaluated, he has no behavior here, definite or otherwise. (The fact that, unlike x , &*x not an lvalue, does not matter here.)
And in C89 / C90 this special case rule has not yet been added, therefore the behavior of &*x is undefined if x is a null pointer (or otherwise invalid). Most pre-C99 compilers will probably optimize the * and & ; remember that the nature of undefined behavior is that something can behave as you might expect it to behave.
On the other hand, there is a very real difference in the behavior of anyone reading the code. If I see y = x; , my behavior should be thinking "Oh, this is the usual pointer assignment." If I see y = &*x; , my behavior is to think "Why did you write like that?" And change it to y = x; if I am able to do this.