Pointer Variable
Finding Address
Let's look back at the variable a
we have before.
Variable | |
---|---|
1 2 |
|
Now, we want to be able to retrieve the address of variable a
.
How can we do that?
C provides an operator called the address operator using the &
symbol ( the symbol is called the ampersand).
We can print the variables using the format specifier %p
.
This will print the address in hexadecimal1.
Address.c | |
---|---|
1 2 3 4 |
|
Try running the code in "ReplIt" tab above and you will see that address will be different each time you run it. This is actually intentional to secure against some type of security attacks. This technique is called address space layout randomization also called ASLR.
Of course, even without ASLR, the address is never guaranteed to be the same between two different runs of the same program. This is because the system will simply allocates any free memory currently available to the program. Depending on what other programs are running, that free memory might be different.
Declaring a Pointer
Syntax
<data type> *<pointer name>
;
The magic symbol here is the star (i.e., *
).
Here, the <pointer name>
is the name (i.e., identifier) of the pointer variable.
The <data type>
is the data type of the variable that this pointer may point to.
A good practice is to name a pointer with a suffix _ptr
or simply _p
.
Integer Pointer Declaration | |
---|---|
1 |
|
Remember how we can declare multiple variables in a single line? We can also do the same for pointer variable. Unfortunately, this can quickly lead to confusion if you are not used to pointer.
First, we will show a simple unambiguous case of multiple declaration involving a single pointer variable.
Unambiguous Pointer Declaration | |
---|---|
1 |
|
Here we can see that variable a
is an integer and a_ptr
is a pointer to an integer.
Now, what happen if we reverse the order and add a little twist to the spacing?
Confusing Pointer Declaration | |
---|---|
1 |
|
Obviously, the type of a_ptr
is a pointer to an integer.
But what about the type of a
?
In this case, the type of a
is still an integer.
So, how do we declare multiple pointer variables in a single declaration?
We will have to put the *
for each of the name to make the variable into a pointer variable.
Multiple Pointer Declaration | |
---|---|
1 |
|
Good Practice
As a good practice, always put the *
before the name instead of after the type.
Although both are accepted, the latter may create confusion as our brain tend to group consecutive characters together.
Assigning Value to a Pointer
Like any other variable in C, the value of an uninitialised variable should be considered to be random value.
We need to assign a value to the pointer variable to ensure that the pointer indeed points to a useful address such as the address of a variable and not some random memory location.
Since we have seen that the address of a variable is randomised at the start of the program execution, you can see the benefit of using the &
operator.
Unitialised Integer Pointer | |
---|---|
1 2 3 |
|
We can also combine the declaration and initialisation similar to how we can initialise a variable during declaration.
Initialised Integer Pointer | |
---|---|
1 2 |
|
Box-and-Arrow Diagram
A simple graphical representation of a pointer is the box-and-arrow diagram.
If we can look at the actual memory used by a program, we may see something like the table below.
Note that we exclude the type since we are not currently interested in the type.
We assume the code "Unitialised Integer Pointer" is being run and that the variable a
is allocated the address ffbff7dc
.
Address | Name | Value | Comment |
---|---|---|---|
ffbff7dc | a |
123 | Variable a at ffbff7dc with value 123 |
ffbff7ff | a_ptr |
ffbff7dc | Variable a_ptr at ffbff7ff with value ffbff7dc |
We can also draw the memory using boxes. However, as we do not really care about the actual value of the address (remember, the address is randomised anyway), we only care about which variable the pointer is pointing to.
This means that the diagram can be simplified further.
In particular, the content of the box a_ptr
can be anything.
But to show that it is pointing to the box a
, we simply draw a literal pointer using arrow.
Accessing Variable Through Pointer
Once we have created a pointer a_ptr
that points to the variable a
(as above), we now have two access points to the variable a
.
The first is the usual direct access using the variable name and the second is indirect access using the pointer variable a_ptr
.
Indirect access is done using the indirection operator (a.k.a. dereferencing operator) using the *
symbol.
Deref.c | |
---|---|
1 2 3 4 5 6 7 8 9 10 |
|
Star (*
)
Note that the star symbol (*
) has two meanings depending on the context of usage.
- Variable Declaration: Creates a pointer variable.
- Variable Usage: Accesses the variable pointer pointed to by the pointer variable (i.e., indirect access or dereferencing).
Note that the second usage is basically anywhere except variable declaration.
Common Mistake
What is wrong with the following code?
CommonMistake.c | |
---|---|
1 2 3 |
|
Unfortunately, the "ReplIt" tab does not show the error because it is compiled with Clang that is doing a smart initialisation. Try the following:
- Click the "ReplIt" tab, and the the "Shell" tab.
- Compile with GCC using
gcc main.c
- Execute the code using
./a.out
You should see Segmentation fault (core dumped)
.
This is caused because the pointer variable n
is not pointing to any valid variable!
In fact, if you draw the box-and-arrow diagram, you will not know where to connect the arrow to.
If you run this on your own computer, remove the file core
from your directory as it takes up a lot of space.
-
You can also try to print it using
%d
, but the compiler will give you a warning. ↩