What is a pointer?

What is a pointer?

No but really, what is it?

A pointer is a number, this number represents an address in the computer's memory (RAM) that stores a value.

Before we dive into the details of what this means and how it works, let's take a look at the following C code in which we are declaring the variable letter of type char and printing it out to the screen.

#include <stdio.h>

int main(){
  char letter = 'b';
  printf("%c\n", letter); // b
}

After this program gets compiled and we get the executable version, we can run it in order to obtain the desire output, the process looks something like this.

Captura de pantalla de 2021-02-14 22-28-56.png

  1. Pick the file app.exe to run the program, which is a program store in the computers hard drive.
  2. All the instructions to run it will be passed from the hard drive to the RAM.
  3. Once there, the RAM will pass each instruction to the CPU and it will execute them as they are received.

We'll focus on step two and how it relates to pointers for the rest of this article.

Bytes and their addresses

If we analyze the way that C interacts with the RAM of a computer we stumble with the concept of bytes, a byte is a unit of digital information that most commonly consists of eight bits. With this in mind we can divide the amount of RAM at our disposal from GB into bytes, to give an example a modern computer might have 8 GB of RAM and that will be equivalent to 8589934592 bytes, and we can manage the memory of a computer by accessing these bytes.

Let's return to this line from our example:

  char letter = 'b';

When running C programs the computer must allocate a certain amount of bytes for every variable that is used in the program, what determines this amount is the type of data that the variable holds. In this particular line the computer will allocate 1 byte of RAM for the variable letter because it is holding a character value, here you can see how many bytes are assigned for the different data types in C.

Data TypeMemory (Bytes)
Short int2
Unsigned short int2
Unsigned int4
Int4
Long int4
Unsigned long int4
Long long int8
Unsigned long long int8
Signed char1
Unsigned char1
Float4
Double8
Long double16

We can check the amount of bytes that a variable takes in memory using the sizeof method.

char letter = 'b';
printf("%d\n", sizeof(letter)); // 1

Every single byte has a number that serves as the address of that particular byte, here's how we can visualize it.

Captura de pantalla de 2021-02-14 23-12-46.png The rectangle container with the green bold border represents the RAM of the computer, and each sub rectangle represents a byte, every byte has an address that is represented by a number. Now, because every byte has a unique address we can see the address of the bytes where our variables are located, we can access and print that address using the & operator.

  char letter = 'b';
  printf("%d\n", sizeof(letter)); // 1
  printf("%d\n", &letter); // A number, the byte's address

It is important to say that every time you execute this and any program the addresses of the bytes that store your variable's values will change, this is because every time you execute the program, the RAM has to take the instructions to run it form the hard drive and deliver those to the CPU, even though it's performing the same task, from the computer's perspective it's a hole different process and that's why the addresses will change. How the computer picks which bytes to assign to a variable in a given moment it's beyond the scope of this article.

For now all you need to know is that every time a program get's executed the computer will allocate a certain amount of bytes to each variable to store it's values, the amount of bytes will depend on the data type of a given variable. Each byte has a number that is it's unique identifier or it's address in the memory.

Making use of the address

Going back to the definition at the beginning of this article, a pointer is a number that represents the address of a byte in the computer's memory. A pointer itself is a variable holding a value, and that value will be the address of some byte. This is how you create a pointer in C:

 char letter = 'b';
 char* pLetter = &letter;

The variable pLetter is holding the value of the address of the byte in which the value that letter holds is stored. We can test this by printing the address of letter using the & operator and printing the value of pLetter . Note that in this example I'm putting the number that resulted by me calling this program, you will get a different one, it doesn't matter, what matters is that you get the same number on both print statements.

  char letter = 'b';
  char* pLetter = &letter;
  printf("%d\n", pLetter); //1197583807
  printf("%d\n", &letter); //1197583807

As you can see both statements print the same address, other thing we can do with pointers is to see the value stored in a given address, for instance, the pLetter variable is a pointer holding the address of the the byte where the value of letter is stored, we can use this address to access the value that resides in that address using the * operator (asterisk), here's what it would look like:

  char letter = 'b';
  char* pLetter = &letter;
  printf("%c\n", *pLetter); //b

Because pLetter holds an address (a number), what the asterisk operator does is telling the computer to go to that address and look up the value that is stored there. We can also change or interact in different ways with the value that is in the address that a pointer points to, if we want to change the value of letter from b to c, we can do so by using the pointer variable pLetter.

char letter = 'b';
char* pLetter = &letter;
*pLetter = 'c';
printf("%c\n", *pLetter); //c

Here's what is going on in the above code. We declare the letter variable of type char and assign to it the value of b, then we create a pointer pLetter that will hold the value of the address in which the value of letter is stored, we then access the value located on that address and change it from b to c, after that we print the value stored at the address that pLetter points to. Note that this address didn't change but the value that reside in it changed, here's an example to visualize it.

Captura de pantalla de 2021-02-15 10-59-29.png

In the image we give the example that the address of letter is the byte 500 and the address of pLetter is the byte 560, pLetter can access the value at address 500 and change it.

And now if we were to print the value located at the address of letter we will get c not b.

char letter = 'b';
char* pLetter = &letter;
*pLetter = 'c';
printf("%c\n", letter); //c

And we can also check that the address didn't change, but the content did.

 char letter = 'b';
 char* pLetter = &letter;
 printf("%d\n", pLetter); //856728143
 printf("%d\n", &letter);//856728143

 printf("%c\n", letter); // value at address 856728143 is b

 *pLetter = 'c'; // change the value at address 856728143

 printf("%c\n", letter); //c
 printf("%d\n", &letter);//856728143

To wrap this up, you should also be aware that a pointer has an address that we can also point to, using, a pointer.