Originally published by Robert Beisert at fortcollinsprogram.robert-beisert.com

Linux + C – Introducing Pointers

You’ve likely noticed the * symbol showing up in our code. Time to look at what that means.

Value and Reference

There are two kinds of data in a program: values, references to a value. We already know how to create a value object, because basic data types such as int and char are value objects. When we create these objects, we deal directly with the values they contain.

However, when we pass a value object into a function, we end up creating a copy of that value within the function (Pass-By-Value). This means that our function cannot change the original value in any way. Sometimes this is very useful. Sometimes it’s not.

pass by value
Pass by Value – We create a one-way transfer of data from the object into our function

When we want to change the original values, we have to pass the function a reference to the data. The function copies that reference, then is able to look up and modify the data in its original location. This is called “pass-by-reference” and is fundamental to a host of applications.

Pass by Reference
Pass by Reference – We create a flow of data between our object and our function


A pointer is a number which represents the memory location in which a value is stored. Pointers are a fixed size determined by the size of your memory, so we can use the same sized pointer to an 8-bit character as to a 2GB file.

When we declare a pointer, we use the asterisk (*) symbol. You’ve seen it when we deal with strings:

char * this_string = “This is a stringn”

From that point on, whenever we use this_string, we are using a pointer to some character (or set of characters – that’s a topic for later).

The same is true of all data types. We can create a pointer to an integer like this:

int value = 5;

int * pointer = value;

References and Dereferences

We use two different syntaxes for declaring pointers and using them. NEVER FORGET THAT. This is the part that confuses most people, so pay close attention.

We can imagine the relationship between objects and pointers to be like Russian nesting dolls: we have data at the core, and we can wrap pointers around them as many times as we want.

When we want to open up one doll (that is, get closer to the data), we use the asterisk (*) again. This symbol lets us point back to the previous level. For example, the code:

int value = 5;

int * pointer = value;

printf(“%dn”, *pointer);

will send the data from value to printf(). It does this because the pointer is pointing directly to the value.

When we want to wrap another doll around the stack (that is, get further away from the data), we use the ampersand (&) symbol. This symbol refers to the location of the object in question. For example, the code:

int value = 5;

int * pointer = value;

if(&value == pointer)

printf(“This is the answer”);

will always print, because the number stored in pointer is equal to &value.



This is a hard topic to understand, so we’ll take it slow at first. We’re going to look at the relationship between pointers and values in the following code.

When you run this program, notice what the results are. We can see that we can find the values of both pointers and our data using any of the other elements. The relationship looks something like this:


#include <stdio.h>

int main(int argc, char *argv[])
    int item = 5;
    int *pointer_to_item = &item;

//We can create pointers to pointers. The principle is the same.
    int ** pointer_to_pointer_to_item = &pointer_to_item;

//When we have a pointer to a pointer, we use two asterisks to get back to the item
    printf("ITEM: %d/t%d/t%d/n", item, *pointer_to_item, **pointer_to_pointer_to_item);

//Notice how we use %p to refer to pointers. This is the best way to print them out.
    printf("Pointer: %p/t%p/t%p/n", &;item, pointer_to_item, *pointer_to_pointer_to_item);
    //We can't do a double ampersand (&amp;) so easily, so there is no &amp;&amp;item
    printf("Dereferenced: /t%p/t%/p/n", &pointer_to_item, pointer_to_pointer_to_item);

    return 0;