DEV Community

Cover image for Understanding the pointers in C
Chamal Randika
Chamal Randika

Posted on • Edited on

Understanding the pointers in C

Hello coding pals ๐Ÿ‘‹

Today I'm going to give you a comprehensive yet simple guide to pointers in C.

Before proceeding, make sure you are alt-east familiar with some basic c syntaxes like printf, scanf, main and user defined functions.

Understanding this will help you to deal with pointers in other languages as well. ๐Ÿ˜Œ

Aright then!, let's begin shall we?

First of all, what's a pointer?

Our computer programs are usually using the main memory(RAM) when they are executing.

The variables we assign in programs are stored in the main memory.

So, when a variable is stored in the main memory, there is an address for that memory location where the variable is located in our main memory.

That address is what we use to access the value which stored in that variable.

A pointer's job is to provide a point to that exact address so we can access the value in that variable.

Pointers visual representation - credits: GeeksforGeeks

image credit: geeksforgeeks.org

The above image shows the difference between a pointer variable and a normal variable that pointer points to.

NOTE: A pointer variable also occupies system memory, which gives it a memory address too. so we can even create another pointer variable to an already specified pointer variable as well.

So simple terms, a pointer is a variable that stores a memory address.

Enough theory, now let's jump into practical examples to better understand how pointers works in a programming environment.

We're going to use C as our programming language since it's one of the few languages that offers direct memory manipulation where proper use of pointers are needed.

#include <stdio.h>

int main()
{
    int b = 42;

    int *a;

    return 0;
}
Enter fullscreen mode Exit fullscreen mode

Study the above code.

Inside our main function, I have created a int type variable named b which stores the value 42.

after that, I have created another int type variable named *a.

You'll notice few differences in the declaration syntax.

* means make it a pointer, So *a means make a a pointer. And int means a is going to point to int values.

With the above code nothing will happen actually. Bcuz we're just telling a is an int pointer. We haven't tell it to where it should point to.

Let's see how we do that now.

#include <stdio.h>

int main()
{
    int b = 42;

    int *a = &b;

    return 0;
}
Enter fullscreen mode Exit fullscreen mode

Now in the above code you'll notice I have added another thing to the end of the pointer variable declaration.

This & operator is used to get a memory address of a certain variable.

So &b means we are telling to get the memory address of b.

So, the complete line int *a = &b; means to create a pointer variable named a that points to an int value and assign the memory address of b to it.

Theoretically, now *a should have the exact memory address of b.

We can verify this by printing the both b's memory address and *a's memory address.

#include <stdio.h>

int main()
{
    int b = 42;

    int *a = &b;

    printf("b: %d\n", b); // prints the value of b
    printf("&b: %p\n", &b); // prints the memory address of b
    printf("a: %p\n", a); // prints the value of a

    return 0;
}
Enter fullscreen mode Exit fullscreen mode

If compile and run the above code, You'll get the following output. (your memory addresses may be vary)

b: 42
&b: 0x7ff7b3c403c8
a: 0x7ff7b3c403c8
Enter fullscreen mode Exit fullscreen mode

You can see that both value of &b and value of a are equal.

This what happens when we create a pointer variable and point it to another variable.

There's another thing you need to know.

We can de-reference a pointer

De-referencing a pointer means accessing the value stored at the memory address pointed to by that pointer

by doing that, we can refer back a pointer and modify the contents of the variable that it points.

#include <stdio.h>

int main()
{
    int b = 42;

    int *a = &b;

    printf("b: %d\n", b); 
    printf("&b: %p\n", &b);
    printf("a: %p\n", a);

    *a = 50;

    printf("b: %d\n", b); 
    printf("&b: %p\n", &b);
    printf("a: %p\n", a);

    return 0;
}
Enter fullscreen mode Exit fullscreen mode

In the above code, I have added a few changes from the previous code.

The *a here is not telling to change value of a. Instead this tells to go get what a is pointing to and use that.

And with the rest of the code in that line, *a = 50; tells the program to go get what a is pointing to and change the value of it to 50.

Output of above code will look like follows,

b: 42
&b: 0x7ff7b76443c8
a: 0x7ff7b76443c8
b: 50
&b: 0x7ff7b76443c8
a: 0x7ff7b76443c8
Enter fullscreen mode Exit fullscreen mode

You'll see that only the value of b has changed. The memory addresses stay the same.

This is how de-referencing is done using a pointer.

But what's the purpose of this huh?

  1. The scanf function

Scanf is a built in function in C that use the advantage of pointers to read values from an input.

Let's see an implementation of it

#include <stdio.h>

int main()
{
    int a, b, c;
    a = b = c = 0;

    printf("Enter 3 numbers:");
    scanf("%d %d %d", &a, &b, &c);
    printf("Result: %d\n", a + b + c);

    return 0;
}
Enter fullscreen mode Exit fullscreen mode

In the above code, What scanf does is, it's accepting 3 inputs from the user %d %d %d(integers) and store them into a, b and c.

You'll notice that we have assigned 0 to all a, b and c.

But if you run this code you'll see that scanf somehow modified the variables and provide the output as the addition of all three numbers.

Enter 3 numbers:2 5 3
Result: 10
Enter fullscreen mode Exit fullscreen mode

So how does scanf is able modify the a, b and c?

What scanf function does is, it gets the values of &a, &b, &c instead of a, b, c.

If you provide a, b, c you just giving the values of those variables which are 3 zeros.

By providing the variables as &a, &b, &c to the scanf, it can point to the addresses of the variables and modify them with the user assigned values.

This is known as a pass by reference.

Since this is built in function we don't see what's happening inside the scanf.

To get a clear idea, we'll create our own simple pass by reference function.

#include <stdio.h>

void swap(int *a, int *b);

int main(void)
{
    int x, y;
    x = 5;
    y = 10;

    printf("x: %d, y: %d\n", x, y); //before the sawp
    swap(&x, &y);
    printf("x: %d, y: %d\n", x, y); //after the swap

    return 0;
}

void swap(int *a, int *b)
{
    int temp = 0;
    temp = *a;
    *a = *b;
    *b = temp;
}
Enter fullscreen mode Exit fullscreen mode

In the above code, we have created a swap function which accepts addresses of variables as int pointers.

Simply said, when we pass the &x and &y to swap function following thing happens first,

int *a = &x

int *b = &y

Familiar that?

That's what we did before de-referencing in the code where I explained the de-referencing.

After that, inside the swap function, whatever we do with *a and *b will happen using the values of the variables x and y.

temp = *a; will assign 5 to the variable temp

*a = *b; will assign 10 to *a.

*b = temp; will assign 5 to *b.

So the final result of the code will display as follows,

x: 5, y: 10
x: 10, y: 5
Enter fullscreen mode Exit fullscreen mode

First line prints the values before swap and the next line prints the values after swap.

If want to see how memory addresses are de-referred, you can add two more print statements as below in the code.

#include <stdio.h>

void swap(int *a, int *b);

int main(void)
{
    int x, y;
    x = 5;
    y = 10;

    printf("x: %d, y: %d\n", x, y); //before the sawp
    printf("&x: %p\n&y: %p\n", &x, &y); // addresses of x and y
    swap(&x, &y);
    printf("x: %d, y: %d\n", x, y); //after the swap

    return 0;
}

void swap(int *a, int *b)
{
    printf("a: %p\nb: %p\n", a, b); // addresses of x and y
    int temp = 0;
    temp = *a;
    *a = *b;
    *b = temp;
}
Enter fullscreen mode Exit fullscreen mode

Newly added print inside the main function prints the memory addresses of x and y.

Newly added print inside the swap function prints the memory addresses of pointed by *a and *b.

Output will be shown as below.

x: 5, y: 10
&x: 0x7ff7bf5af3c8
&y: 0x7ff7bf5af3c4
a: 0x7ff7bf5af3c8
b: 0x7ff7bf5af3c4
x: 10, y: 5
Enter fullscreen mode Exit fullscreen mode

You can see now memory addresses of x and y matches the memory addresses of *a and *b.

That means *a and *b are pointing to x and y.

So, by using *a and *b, you can manipulates the values of x and y inside the swap function without affecting the memory addresses.

This is how a pass by reference works.

There are many cool stuff you can do with pointers in C.

But, I don't want to make this article very lengthy.๐Ÿ˜Š

So, let's see how pointers help the dynamic memory allocation in a future article.โ˜๏ธ๐Ÿ˜Œ

Till then, โœŒ๏ธ

Top comments (0)