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.
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;
}
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;
}
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;
}
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
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;
}
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
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?
- 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;
}
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
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;
}
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
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;
}
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
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)