Pointers in C Programming: Everything You Need to Know

Pointers in C Programming: Everything You Need to Know

Understand what pointers are and how they work in C programming

Play this article

Introduction

Pointers just like any other word that look like it, such as washer as someone that washes etc. also mean something that points.

Pointers in C are simply variables that point to the address of other variables in memory. For example, let's say you have a house, your house is on land, and the land is in a street, the street is in a city and the city is in a country, now for anyone to be able to get to your house, they need to get the full address of your house, which will give the exact location of your house in that area. What points to the location of your house is simply the address, so we can say that if anyone wants to direct or point other people to your house, He first needs to know the address of your house, which He can then confidently point the people to your house, since He has the address of your house, in that sense, we can refer to the person as a pointer.

So also in C Programming, every variable declared has a space in memory that is reserved for it. And that space in memory can only be accessed using an address of the location where that memory is situated, now a pointer is what holds the address of that memory location where the declared variable is stored.

So simply put, Pointers in C are variables that store or hold the address of the location where a variable declared is stored in memory.

It holds the memory location of where the variable is located or stored.

Why Use Pointers?

Now there may be questions brewing in your mind as you go through the introduction, the question of what is even the use of accessing the memory location of where a variable is stored. This heading will answer that question in a clear and precise manner.

Pointers have various advantages and uses, and some of them are:

  1. Dynamic Memory Allocation

    Pointers are essential in dynamic memory allocation in C, this is where malloc, calloc, realloc and free comes in, without pointers, it will be practically impossible to do that. As each of them returns and operates on pointers.

  2. Efficient Memory Usage

    Pointers help to make efficient use of memory in the sense that instead of copying large chunks of data, most especially in big programs, the memory address of such data can be passed instead.

  3. Data Structures and Algorithm

    Pointers also play a very vital role in the implementation of some complex data structures and algorithms, such as linked lists, stacks, queues and trees.

  4. String Manipulation

    Since strings are considered to be arrays of characters, Pointers can be used to manipulate strings to perform things like string concatenation, string comparison etc.

  5. Pointers also enable one to be able to change the value of a variable multiple times directly from the memory address without re-assigning another variable to do that.

There are other uses of pointers in C programming, but these are the basic ones for now.

Declaring and Initializing Pointers

Declaring a Pointer Variable

From the introduction, you saw that a pointer itself is also a variable, but unlike other variables that hold a value, in terms of maybe an integer, float, char etc. Here, the pointer stores a memory location called address.

Although there is a similarity between the normal variable and the pointer variable, they still have their uniqueness.

The pointer variable must always be declared with the same data type as the variable whose address it is pointing to.

That is to say, if we have a variable declared as int num, to create a pointer that points to the address of num, it also has to be declared as an int. If the variable is declared as a char, then the pointer to the variable must also be declared as a char.

Another thing is that the pointer variable must be declared with an asterisk '*' that can be situated immediately after the data type is combined. or a space between the data type and variable or immediately before the pointer variable combined.

For Example:

#include <stdio.h>

int main(void)
{
    int number;
    number = 25;

    int* ptr_num; // first approach
    int * ptr_num; // second approach
    int *ptr_num;    // third approach

    return (0);
}

from the code above, the ptr_num is the pointer variable that is declared to hold the address of the number variable, you can see that because the number has a data type of int, the pointer variable ptr_num that is to hold the address of the variable number has to be declared with an int data type too.

Concerning the approach of declaration, I prefer the third approach, but any one of the three approaches will work.

Let us also look at a similar example, where the variable this time around is having the char data type:

#include <stdio.h>

int main(void)
{
    char initial;
    initial = 'G';

    char* ptr_initial;     // first approach
    char * ptr_initial;    // second approach
    char *ptr_initial;     // third approach

    return (0);
}

The same thing happens here too because the pointer will be pointing to the name, which has a char data type, so also the pointer must have a char data type.

Initializing a Pointer Variable

To Initialize a pointer variable after the declaration, we use an ampersand symbol '&' attached to the variable whose address we want to store in the pointer variable.

For example:

#include <stdio.h>

int main(void)
{
    int number;
    number = 25;

    int *ptr_num;        // declaring a pointer
    ptr_num = &number;    // initializing a pointer

    return (0);
}

In this example, after declaring the pointer variable ptr_num, we then go ahead to initialize it using the ampersand symbol together with the variable we are pointing to, so we have ptr_num = &number.

Know that we can also declare and initialize the pointer all in a single expression:

#include <stdio.h>

int main(void)
{
    int number;
    number = 25;

    int *ptr_num = &number;    // declaring and initializing a pointer

    return (0);
}

This is how to declare and initialize a pointer.

Referencing and Dereferencing Pointers

The idea behind referencing and dereferencing pointers is that when a pointer is used to store the address of another variable in memory, it is been said that the pointer is referencing the variable. Since it points directly to the memory location of the variable to which it is pointing.

Whereas, when we intend on getting the value stored in the variable which the pointer is pointing to, we need to do what we call a dereferencing.

Referencing a Pointer

Referencing a pointer is simply the same as declaring and initializing the pointer. When a pointer points to the address of the memory location of a variable, it is said to reference the variable. Hence, the declaration and initialization of a pointer are the same as referencing a pointer. For example:

#include <stdio.h>

int main(void)
{
    int number;
    number = 25;

    int *ptr_num = &number;    // referencing the pointer ptr_num

    return (0);
}

The example above is known as referencing of a pointer.

Dereferencing a Pointer

While dealing with pointers, there are instances where one might want to access the value that is stored in the variable that is been pointed to by the pointer, in this case, we will have to do what is called dereferencing.

This dereferencing is almost the same as the declaration of the pointer, that is we attach an asterisk to the pointer variable name, only that it serves two purposes; which are to access the value stored in the variable which the pointer is pointing to, and secondly can also be used to modify (change) that value as well to another value. Of course, the new value will have to be of the same data type as the initial value. You can't simply just change a value with an int data type to another with a char data type, that won't work. For example:

#include <stdio.h>

int main(void)
{
    int number;
    number = 25;


    int *ptr_num = &number;    // referencing the pointer ptr_num

    int new_number = *ptr_num;

    return (0);
}

From this example above, we dereferenced the pointer variable ptr_num and then stored the value in the variable new_number.

Note that some books on C programming will tell you that declaring the pointer variable on the left-hand side is the same as referencing it while doing the same thing by the right-hand side of the expression to the '=' sign is simply dereferencing it, but in reality, you don't even need an equal to '=' sign to dereference a pointer, you can simply do it right away. For example:

#include <stdio.h>

int main(void)
{
    int number;
    number = 25;


    int *ptr_num = &number;    // referencing the pointer ptr_num

    int new_number = *ptr_num; // dereferencing the pointer ptr_num
                               // to get the value of number
    printf("*ptr_num: %d\n", *ptr_num);
    printf("new_number: %d\n", new_number);

    return (0);
}

From the equation above, you can either store the value of the variable the pointer is a pointer to in another variable by declaring it to the right as in dereferencing it into the new variable, before printing out the value to standard output using the printf, or you can simply just dereference it and print the value at the same time.

This will give us the same answer, which in this case is 25, as that is the value of what the pointer ptr_num is pointing to.

Changing Values of Variables Using Pointer

Just like how we can dereference a pointer to get the value of the variable it is pointing to, so also we can dereference a pointer to change the value of the variable it is pointing to. It is a very efficient way of updating our variables without having to create new variables. It also helps update the value most especially in large programs such as games etc, where there is a constant change in values like level, scores, points, life level etc.

Here is an example of how to do that:

#include <stdio.h>

int main(void)
{
    int number;
    number = 25;

    int *ptr_num = &number;    // referencing the pointer ptr_num

    printf("\nBefore Change\n");
    printf("*ptr_num: %d\n", *ptr_num);
    printf("Number: %d\n", number);

    *ptr_num = 48;
    printf("\nAfter Change\n");
    printf("*ptr_num: %d\n", *ptr_num);
    printf("Number: %d\n", number);

    return (0);
}

From our code, we simply dereferenced ptr_num and updated the value of the number variable which initially was 25, but now is 48.

Memory Address of Pointers

We have been talking about pointers carrying memory addresses of variables. Now what is that memory address, it is simply a string of integers in base 16 that shows a location in the memory. When we keep saying memory, remember that in the Computer world, your computer memory can also be referred to as your computer RAM (Random Access Memory), whereas storage is known as your ROM (Read Only Memory). And to print the memory address, we have to use the %p identifier using the printf function in C.

So let us see how to print or display this memory address.

Note that the value of the memory address will always be different for different machines and changes with every compilation you run on the same code, so don't panic if what you will see displayed in this article is quite different from what you see on your machine.

#include <stdio.h>

int main(void)
{
    int number;
    number = 25;

    int *ptr_num = &number;    // referencing the pointer ptr_num

    printf("\nBefore Change\n");
    printf("*ptr_num: %d\n", *ptr_num);
    printf("Number: %d\n", number);
    printf("ptr_num: %p\n", ptr_num); // memory address of number
    printf("&number: %p\n", &number); // memory address of number

    *ptr_num = 48;
    printf("\nAfter Change\n");
    printf("*ptr_num: %d\n", *ptr_num);
    printf("Number: %d\n", number);
    printf("ptr_num: %p\n", ptr_num); // memory address of number
    printf("&number: %p\n", &number); // memory address of number

    return (0);
}

I decided to use the same code I used to change the value of the variable number to show you that if you check before and after the change, the memory address of the variable number remains unchanged because we just updated it directly using pointers.

Why I decided to print it two times both before and after the change is to show that you can access the memory address of the number either by using the pointer pointing to the variable, which in this case is the ptr_num, or by using the variable directly, but with an ampersand preceding it.

Conclusion

There is so much we can do with pointers, we can combine them with arrays, functions, and structs, use them as function parameters and as arguments to functions, return them from a function and many more. We will be touching one after the other.

Thank you for reading. You can connect with me on Twitter and LinkedIn.