Exploring Pointers in C — A Beginner’s Guide

Emmanuel Adebanjo
8 min readJun 26, 2023

--

Hi guys, before we delve into the world of pointers and pointing :) I would like for us to delete every notion that pointers are hard. Confusing maybe, but that’s the purpose of this article, to demystify the concept of pointers. Pheeew, now that that’s out of the way and we have the right mindset…

What is a Pointer?

A pointer does what the name implies, it points :). In C programming language a pointer in its most basic form points to and stores the address of a variable. I know, I know, we’ve been speaking English so far, now let’s speak C.

How do I declare a pointer?

Whenever you see an asterisk (*) after a data type or before the variable name in C, we are dealing with pointers. Still English right :)…

int main(void)
{
int* c;
char* c;
float* c;
double* c;
//Write some codes
return (0);
}

OR

int main(void)
{
int *c;
char *c;
float *c;
double *c;
//Write some codes
return (0);
}

Those are two syntaxes to declare pointers in C. I prefer the syntax in the second image for no particular reason. Although, most programmers prefer the syntax in the first image. Go with whatever syntax works for you, neither is more correct than the other.

We’ve been talking about addresses, let’s see what it looks like when a pointer points to the address of a variable in C.

Declaring a Pointer in C

Hol up, hol up :), I know there are a lot of things I haven’t explained in the codes. Let’s break the code down:

  • First, we declare an integer variable x and assign it a value of 10.
  • Next, we declare an integer pointer a. A pointer would only point to a variable of the same type as itself. Please see the image below;
Pointer Types

A pointer would only point to the same data type as itself. For instance, an integer pointer would not point to a char data type. The only exception to this rule is a void pointer, which can point to any type.

  • Next, we set the integer pointer a to point to the address of x. The ampersand (&) symbol in C and the world of pointers mean “Address of”. This implies, that a pointer cannot just determine the address of a variable by some magic :), we have to assign the pointer to the address of (&) the variable we want it to point to.
  • Next, we print out the address of where the variable x is stored in the memory, using the %p format specifier. This format specifier is used to print memory addresses. Also, you would notice that we used the void pointer to cast the integer pointer a, this is because the argument corresponding to %p in print must be of type void pointer.

Here’s our output:

Please note, that the memory address we describe here is the stack memory and not the heap memory. I would not go into much detail about the differences and use cases of stack and heap memory in this blog post, but hopefully, someday I might write about it 😊. For now, know that stack memory is a temporary storage memory, which has a fixed size allocated by the compiler or computer While dynamic memory is also a temporary storage but allows the programmer to allocate memory with malloc and free at runtime.

Brace up, let’s go deeper 💪

I know, I know… I know I had said pointers store the address of the variable it points to. This is true and in fact, is the primary responsibility of the pointer. But we could say the pointer has extra abilities, in that we can get to the value stored in the address of the variable it points to. How???

Dereferencing

Dereferencing helps us get to the value stored in a particular address pointed to by a pointer variable. To define dereferencing, this is the process whereby the data stored in the address of the variable pointed to by the pointer can be accessed from the pointer itself. Hmm, let’s write some codes…

int main(void)
{
//declaring a pointer of type int
int *a;

//declaring an integer x and storing the value of 10 in it
int x = 10;

//We set a to point to the address of where x is stored.
a = &x;
//DEREFERENCING DEREFERENCING DEREFERNCING
printf("Value of x is %d\n", *a):
return (0);
}

Here the result will be, “Value of x is 10”. This is possible because of dereferencing. To dereference a pointer all we need to do is *name_of_pointer after the pointer has been declared and assigned to point to a variable. So, adding an asterisk (*) to the name of the pointer after the declaration and assignment helps us to dereference.

As an exercise run this code on your computer and see the output

#include <stdio.h>
int main(void)
{
/* variable of data type int and with value 10 stored in it */
int x = 10;
/* Pointer of type integer */
int *a;

/* assigning pointer a to point to the address of x */
a = &x;
/**
* Here we print out the value stored in a
* Which is the address of x
*/
printf("Address of a = %p\n", (void *)a);

/* Printing the value of x using pointer a */
printf("Value stored in x = %d\n", *a);

/* Changing the value of the variable x using dereferencing */
(*a) = 20;
printf("Value of x is %d\n", x);
return (0);
}

All things being equal, the last print statement should be “Value of x is 20”. By dereferencing the pointer a, we were able to change the value of x 👌. Let’s go deeper 😄💪

Pointer to Pointer

A pointer can point to another pointer 😭😂, for a pointer to point to another pointer, it must be greater than the pointer it wants to point to. How?

int main(void)
{
// We have an integer variable x, which stores the value 10
int x = 10;
// we have a pointer
int *a;
// we have a double pointer
int **b;
// we have a triple pointer
int ***c;
// pointer a points to the address of (&) integer variable x
a = &x;
// pointer b points to the address of pointer a
b = &a;
// pointer c points to the address of pointer b
c = &b
return (0);
}

Do we see what’s happening here, pointer c which is a triple pointer points to the address where pointer b which is a double pointer is saved, double pointer b points to the address where pointer a is saved, and pointer “a” points to the address of where variable x is saved. Let’s see what dereferencing can do, here…

Notice how all the addresses are the same and that is the address of where variable x is stored on the stack memory. Let’s break this down:

a = &x (this implies that if we try to print a, we’ll get the address of where x is stored).

b = &a (this implies that printing b gives us the address of where a is stored)

c = &b (this implies that printing b gives us the address of where b is stored)

If this is clear;

  • *a (this means, dereferencing a which takes us past the address of the x variable and gives the value stored in x, which is 10 in our case)
  • Remember that b is already the address of pointer a, so dereferencing (*b) takes us past the address of pointer a and leads us to the value stored in a, which is the address of x.
  • Also, remember that c is already the address of b, and dereferencing c twice takes us past the address of pointer b, leads us to the value stored in b which is the address of a, and then takes us past the address of a and leads us to the value stored in a which is the address of x.

Still confusing?? Let’s make one last attempt to demystify the concept of dereferencing. Using the case of the triple pointer, imagine you have a sweet or candy and accidentally the candy company wrapped a particular candy thrice. See the concept of dereferencing as unwrapping the candy.

  • The outermost wrapper is the triple pointer c, Unwrapping (dereferencing) twice takes us to the last wrapper, which in our case is the address of x. What do you think happens if we unwrap (i.e. dereference) one more time? You guessed right 👏, we hit the sweet, which in our case is the value of x, i.e. 10.

Yes, we can get to the value of x using our triple pointer or double pointer or pointer. See codes below;

Do you know that you can change the value of x which is 10 to some other int value using any of our pointers?

I’ll leave that as an assignment for you 👌

Pointers are quite tricky and require constant practice, I still get confused sometimes too 😅. There are still a lot more concepts to explore in the world of pointers such as pointer arithmetics, the relationship between pointer & character arrays, function pointers, and call by reference vs call by value etc.

Conclusion

Please feel free to check out this youtube link to understand pointers even better. The tutor did a fantastic job explaining pointers.

Hit the clap 👏 button if you got to this point. To answer the exercise, I will write about a concept (Call by Value vs Call by Reference) that should give you an idea of how to answer it. Hit the subscribe button to be the first to be notified when I do this. Feel free to leave a comment if you have questions or suggestions and I will respond 👌.

--

--

Emmanuel Adebanjo

I am a budding software engineer who wants to be better everyday, and share some of the knowledge I have gathered and am gathering with the world :)