p
. Examining the value of memory location
"65,532", I find the binary digits "10110100000111110011010000111010".
But, what is its value? Is it an ASCII character? An integer?
A class's data member? A machine instruction from my
swap()
function? It's unclear how to interpret this
string of bits, which is why the compiler must be told (via the
type of the pointer, or an explicit cast) what the type of this
data is. Without this information, the compiler is unable to
interpret this information correctly.
int
i
is immediately after its declaration?). Since pointers
are variables which contain addresses of other memory
locations, this means that an unitialized pointer may refer to
any location in memory, which is very dangerous,
indeed. You could access any memory, from your function's
machine instructions to your operating system's own pool of
protected memory. NEVER ACCESS THE MEMORY THAT AN
UNITIALIZED POINTER REFERS TO.
*
in front of the
variable identifier. For example:
int *ip; double *dp = NULL;This delcares a pointer,
ip
, to an integer. Stated
in another way, ip
is a variable which contains the
address of an integer. The second line delares a pointer to a double,
but initializes the pointer to point to the NULL
pointer.
The NULL
pointer is defined to be invalid memory.
Although attempting to access the memory that NULL
points to will result in a program crash, this is preferable to
accessing memory which does not belong to you. NULL
is useful when checking for error conditions, and many
functions return NULL
if they fail.
int x = 5; int *ip; ip = &x;We first encountered the
&
operator first with
scanf()
. The &
operator is known as
the address-of operator, and yields the memory location
of its argument. Here, the expression &x
evaluates
to the memory location where the variable x
is located.
Thus, the pointer ip
is made to point to x because
ip
was assigned the address of x
.
*
operator. The
*
dereferences (or "accesses the value of")
the pointer. The *
operator tells your computer to
examine the data located at the address stored in the pointer,
and to interpret the bits located at that address as a variable
of type T
, where T
is the pointer's
type. In the following example, the expression *ip
on the fifth line instructs your computer to go to the address
stored in ip
(which happens to be the location of
x
), and to interpret the bits located at this
address as if it were an int
(since the type of
ip
is int
).
int x = 5; int *ip; ip = &x; printf("%d %d\n", x, *ip);This code would print
5 5
to the screen.int x = 0, y = 5, *ip = &y; x = *ip;The statement
int *ip = &y;
is different than
x = *ip;
. The first statement does not dereference,
the *
signifies to create a pointer to an int. The second
statement uses a dereference. In a variable declaration (including,
function argument declarations) *
represents the
declaration of a pointer variable. In any other pointer-related
contexts, *
represents the dereference operator.
swap()
function is probably the most common
example of pointer syntax and usage:
void swap(int *x, int *y) { int tmp; tmp = *x; *x = *y; *y = tmp; } int main(void) { int a = 2, b = 3; swap(&a, &b); return 0; }This snippet of code works. When you call
swap
, you
must give the address-of a and b, because swap is expecting a
pointer (remember, pointers are merely variables containing
addresses, so the arguments to a function which has pointer
arguments should naturally be an address!).a
and b
, which are
located on the stack. The memory for local variables does not
"go away" or get "popped off" after the function
swap
ends (the memory for local variables goes away
at the end of the function call which created them -- in this
case, when main
terminates). Since
swap
does not modify any of its local
variables (it's modifying main
's variables via the
pointers x
and y
), the
changes made within swap
change the values located
in the memory addresses associated with a
and
b
, and that these changes will remain as long as
these variables are valid.const
type qualifier can make things a little
confusing when it is used with pointer declarations. The
general rule-of-thumb is that const
refers to the
thing immediately to its left. If there is nothing to its left,
then const
refers to the thing immediately to its
right.
const int * const ip; /* The pointer is const, and it will not change its pointee */ int const * const ip; /* The pointer is const, and it will not change its pointee */ const int * ip; /* ip will not change its pointee */ int const * ip; /* ip will not change its pointee */ int * const ip; /* ip is const (it will not change what it points at) */ int * ip; /* Nothing is const */As you can see, you must be careful when specifying the
const
qualifier when using pointers!const
pointer is a pointer which cannot
change what data it will point at. Since a pointer is a variable
which contains addresses, a const
pointer cannot
change the address that it contains -- that is, it can only
point at one address. The values at this address, however,
may change.
const
type means that this
pointer will not change the value of its pointee. The pointer
itself, however, may change.
void
pointers are pointers without a type.
Therefore, they may hold the address of any variable,
regardless of type. They may also be assigned to a pointer of
any type, provided that the void
pointer is cast
to the appropriate type. It sometimes necessary to
store/copy/move pointers without regard to the type of the data
it references. void
pointers are most often used
to implement generic reference (similar to Java's
Object
type).void
pointer.
This is because, without type information, your computer does
not know how to interpret the bits which are located at the
void
pointer's address.&
and *
.
The &
operator gives the address of a variable. The
*
dereferences the pointer (when not used in a pointer
declaration statement).const
type qualifier.
You have to also be cautious about the void
pointer.