As everyone else has mentioned, in implementation references and pointers are largely the same. There are some minor caveats:
- You can't assign NULL to a reference
(shoosh mentioned this): that's
significant since there is no
"undefined" or "invalid" reference
value. 
- You can pass a temporary
variable as a const reference,
but it's not legal to pass a pointer
to a temporary.  
For example, this is okay:
class Thingy; // assume a constructor Thingy(int,int)
void foo(const Thingy &a)
{ 
   a.DoSomething();
}
void bar( ) 
{
  foo( Thingy(1,2) );
}
but most compilers will complain about
void foo2( Thingy * a);
void bar2()
{
  foo( &Thingy(1,2) );
}
- Taking the address of a variable to get a pointer forces the compiler to save it to memory. Assigning a reference to a local variable just creates a synonym; in some cases this may allow the compiler to keep the data on the register and avoid a load-hit-store. However, this only applies to local variables -- once something is passed as a parameter by reference, there's no avoiding saving it to stack.
 
void foo()
{
   int a = 5;
   // this may be slightly more efficient
   int &b = a;
   printf( "%d", ++b );
   // than this
   int *c = &a;
   printf( "%d", ++(*c) );
}
- Similarly, the __restrict keyword cannot be applied to references, only pointers. 
- You can't do pointer arithmetic with references, so whereas if you have a pointer into an array then the next element in the array can be had through p+1, a reference only ever points at one thing in its entire life.