A pointer is declared much like any other variable, except an asterisk (\\*) is placed between the type and the name of the variable to denote it is a pointer.

int *pointer; /* inside a function, pointer is uninitialized and doesn't point to any valid object yet */

To declare two pointer variables of the same type, in the same declaration, use the asterisk symbol before each identifier. For example,

int *iptr1, *iptr2;
int *iptr3,  iptr4;  /* iptr3 is a pointer variable, whereas iptr4 is misnamed and is an int */

The address-of or reference operator denoted by an ampersand (&) gives the address of a given variable which can be placed in a pointer of appropriate type.

int value = 1;
pointer = &value;

The indirection or dereference operator denoted by an asterisk (\\*) gets the contents of an object pointed to by a pointer.

printf("Value of pointed to integer: %d\\n", *pointer);
/* Value of pointed to integer: 1 */

If the pointer points to a structure or union type then you can dereference it and access its members directly using the -> operator:

SomeStruct *s = &someObject;
s->someMember = 5; /* Equivalent to (*s).someMember = 5 */

In C, a pointer is a distinct value type which can be reassigned and otherwise is treated as a variable in its own right. For example the following example prints the value of the pointer (variable) itself.

printf("Value of the pointer itself: %p\\n", (void *)pointer);
/* Value of the pointer itself: 0x7ffcd41b06e4 */
/* This address will be different each time the program is executed */

Because a pointer is a mutable variable, it is possible for it to not point to a valid object, either by being set to null

pointer = 0;     /* or alternatively */
pointer = NULL;

or simply by containing an arbitrary bit pattern that isn’t a valid address. The latter is a very bad situation, because it cannot be tested before the pointer is being dereferenced, there is only a test for the case a pointer is null:

if (!pointer) exit(EXIT_FAILURE);

A pointer may only be dereferenced if it points to a valid object, otherwise the behavior is undefined. Many modern implementations may help you by raising some kind of error such as a segmentation fault and terminate execution, but others may just leave your program in an invalid state.

The value returned by the dereference operator is a mutable alias to the original variable, so it can be changed, modifying the original variable.

*pointer += 1;
printf("Value of pointed to variable after change: %d\\n", *pointer);
/* Value of pointed to variable after change: 2 */

Pointers are also re-assignable. This means that a pointer pointing to an object can later be used to point to another object of the same type.