The simplest answer, assuming you don't mind the vagaries and variations in format between different platforms, is the standard %p notation.
The C99 standard (ISO/IEC 9899:1999) says in §7.19.6.1 ¶8:
pThe argument shall be a pointer tovoid. The value of the pointer is converted to a sequence of printing characters, in an implementation-defined manner.
(In C11 — ISO/IEC 9899:2011 — the information is in §7.21.6.1 ¶8.)
On some platforms, that will include a leading 0x and on others it won't, and the letters could be in lower-case or upper-case, and the C standard doesn't even define that it shall be hexadecimal output though I know of no implementation where it is not.
It is somewhat open to debate whether you should explicitly convert the pointers with a (void *) cast. It is being explicit, which is usually good (so it is what I do), and the standard says 'the argument shall be a pointer to void'. On most machines, you would get away with omitting an explicit cast. However, it would matter on a machine where the bit representation of a char * address for a given memory location is different from the 'anything else pointer' address for the same memory location. This would be a word-addressed, instead of byte-addressed, machine. Such machines are not common (probably not available) these days, but the first machine I worked on after university was one such (ICL Perq).
If you aren't happy with the implementation-defined behaviour of %p, then use C99 <inttypes.h> and uintptr_t instead:
printf("0x%" PRIXPTR "\n", (uintptr_t)your_pointer);
This allows you to fine-tune the representation to suit yourself. I chose to have the hex digits in upper-case so that the number is uniformly the same height and the cha
Use %p, for "pointer", and don't use anything else*. You aren't guaranteed by the standard that you are allowed to treat a pointer like any particular type of integer, so you'd actually get undefined behaviour with the integral formats. (For instance, %u expects an unsigned int, but what if void* has a different size or alignment requirement than unsigned int?)
*) [See Jonathan's fine answer!] Alternatively to %p, you can use pointer-specific macros from <inttypes.h>, added in C99.
All object pointers are implicitly convertible to void* in C, but in order to pass the pointer as a variadic argument, you have to cast it explicitly (since arbitrary object pointers are only convertible, but not identical to void pointers):
printf("x lives at %p.\n", (void*)&x);