The unary dereference or 'indirection' operator and the 'address of' operators are asterisk, '*', and ampersand, '&', respectively. These two characters have a different meaning when used as binary operators (multiplication and bitwise AND). Just like unary minus, there is no difficulty in knowing which is to be used because of the syntactic context. But it does mean that certain typing errors will produce a syntactically valid expression but not what you meant!
The indirection operator, i.e. the unary asterisk '*', when used in a declaration tells the compiler that the named variable is a pointer to the type.
int *p, x; /* declaration */
When used in an expression, the operator means, the value of the data object pointed to. That is the value in memory at the address which is the value of (or stored in) the pointer.
*p = x - *p; /* expression statement1 */
The inverse of the indirection operator is the 'address of' operator. It is applied to the left of an expression which must be an 'lvalue', and it gives as value the address of or for that 'lvalue'. Using the two variables declared above, we can set 'p' to the address of 'x' by:
p = &x;
in which case the expression statement1 above would set 'x' to zero.
One can take the address of an entire struct or union or a field of a structure, '&s.f', or of an element of an array, &a[x]. The latter is simply: a+x.
&(*(a+x)) ==> a+x
When a function is passed a simple variable, and that variable is changed, only the function's local copy of the variable is changed. The original variable is unaffected, since only its value was passed to the function. But, if the function's parameter is a pointer to a variable, then the variable can be changed:
void func1(int p) { p = 5 - p; } void func2(int *p) { *p = 5 - *p; } main() { int x; ... func1(x); /* 'x' is unchanged */ func2(&x); /* 'x' is now: 5-x */ ... }