All variables of non-primitive types in Java are references. C has no concept of ‘reference’, but instead has pointers, which Java does not. They are similar, but you can do much more with pointers, with a correspondingly greater risk of mistakes.

A pointer is an address in memory of some ordinary data. A variable may be of pointer type, i.e. it holds the address of some data in memory.

/* We'll assume we're inside some block statement,
   as in a function. */

int i, j; /* i and j are integer variables. */
int *ip;  /* ip is a variable which can point
         to an integer variable. */

i = 10;
j = 20;   /* values assigned */

ip = &i;  /* ip points to i. */
*ip = 5;  /* Indirectly assign 5 to i. */
ip = &j;  /* ip points to j. */
*ip += 7; /* j now contains 27. */
i += *ip; /* i now contains 32. */

The & operator obtains the address of a variable. The * operator dereferences the pointer. While ip points to i, then *ip is synonymous with i, and you can use it in any expression where you could use i. A dereferenced pointer can be used on the left-hand side of an assignment, i.e. it is a modifiable lvalue (‘el-value’), as in the two examples above.

The characters & and * also serve as binary operators for bitwise AND and multiplication, but the pointer operators are unary, so the syntax ensures that there is no ambiguity. Furthermore, it is a common convention to put spaces around binary operators, but not between a unary operator and its operand, so it's usually easy to see what these characters are being used for at a glance.

C doesn't care whether you declare int *ip; or int* ip;. The type of ip is int * (or pointer-to-int) either way. However, some prefer the first form, because it acts as a mnemonic that *ip is an int; while some prefer the second, because it keeps the type separate from the variable name. Note that the * does not propagate across multiple variables in a single declaration, such as int *ip, i;i is still just an int in that case.