I’ve written this post because I see a lot of confusion on the internet about C pointers and it’s almost always a misunderstanding of the basic syntax. So here’s a post explaining the syntax.

For the whole of this post we’re going to ignore the case where * means multiply (when it is placed between two number types).

Random Access Memory (RAM)

To understand what’s going on with pointers you first need to know about how memory works on your computer. If you know this already skip onto the next section.

Your computer has some very fast memory used for running programs, this is called RAM (Random Access Memory). This memory is addressed; this is done by giving each byte a number. The computer can then ask the RAM chip for the data at that address (number) and it’ll get the data. This is why 32 bit systems can only support 4 GBs of RAM; a 32 bit system has an address size 32 bits long, i.e. it only has 2^32 numbers with which to address the RAM (2^32 bytes = 4 Gigabytes).

Addresses

When we use the word address we mean the location (byte number) in RAM of the start of the data we are interested in.

When you create a variable in your program that variable is put into the RAM for the lifetime of the current scope (within the {...} which the variable is declared). This means that your variable has an address, you can get the address using the & symbol. The following code prints the address of variable a:

int a;
printf ("address of a = %#llx \n", &a);
printf ("address of a = %p \n", &a);

%#llx prints up to a 64 bit number in hexidecimal integer with 0x preceeding it. The top print will give you a type warning because the compiler knows that &a has the type of an address at which there is an integer, not type long long int (which is the type we have asked it to print) but as an address is just a number it’ll work without any problems. %p is used to print addresses. If you run this code you will find that both lines will print exactly the same thing, which is the location/address in RAM of a.

Pointers

The first thing to do is to introduce the jargon:

  • A pointer: A variable that contains the address of some area of your RAM.
  • Pointed at: The data at the address of a pointer

I.E. “The thing pointed at by a”: a is a pointer, and we want to talk about the data at the address stored in a)

All you need to know to understand pointers is that * means “the thing pointed at by”. Let’s look at some examples of this:

int a;

This means “a is a variable of type int”.

int *a;

This means “the thing pointed to by a is of type int”.

int *a;
int b = 10;
a = &b;
int c = *a;
  • The thing pointed at by a is an int.
  • b is an int and equals 10.
  • a equals the address of b.
  • c is an int and equals the thing pointed at by a (the int at the address stored in a).

At the end of this c will equal 10.

int *a;
int b = 10;
a = &b;
*a = 15;

This is nearly the same as above except the last line. The last line says:

The thing pointed at by a equals 15. a points at the memory of b so if we printed the value of b at the end of this we would find that it had changed from 10 to 15.

As we can see from the examples every time we see * we can read the thing pointed at by.

You can create and set a pointer in a single line like this:

int a = 10;
int *b = &a;

The second line of this code reads “The thing pointed at by b is an int, and b equals the address of a”. Note that in this case the * only applies to the declaration of b and not to setting b. i.e. This code is equivalent to:

int a = 10;
int *b;
b = &a;

When using * like we have above (both in declarations and when placed in front of a variable) it works on the variable that comes directly after it. So in this case:

int *a;

* changes a, it does not change the type. This means that if you write something like this:

int *a, b;

The code above can be read as b, and the thing pointed at by a are ints. Note that it would seem more natural to write the statement above with a first as this is how we declared it, unfortunately this statement is ambiguous in English, and would need to be read like this: (the thing pointed at by a) and b are ints, taking note of the brackets.

To get a and b to be pointers you need to write:

int *a, *b;

To put this in technical terms * is a unary prefix operator. An operator is a symbol that represents a specific action, unary means that it acts on a single element, and prefix means that is comes directly before the element.

You will see people write code like this int* a, this makes it look like * is changing the type, i.e. changing the type from int to a pointer to an int. This isn’t how C works and the compiler will still read the code like this int *a. Doing int* a is as weird as writing bool a = true; bool b =! a; Note if you did this it would seem like bool c =! a && b would mean bool c = !(a && b).

What’s next

There is loads more to explore about pointers in more detail such as arrays and pointer arithmetic or types/typecasting (especially interesting in an Object Oriented situation such as Objective C or GTK).

Have fun.