Pointers in C
What is a Pointer?
A non-technical explanation would be “A pointer is something that points towards anything.” In programming, a pointer does just that – it “points” to the location in the computer’s memory where some data is stored. This allows us to indirectly access or modify that data. So basically, a pointer points towards the location of something in the computer’s memory.
Declaring a Pointer
Below is the syntax to initialize a pointer in C:
datatype *variable_name;
For example:
int *addr;
Understanding Memory Addresses
Before we proceed further, let’s quickly understand what memory addresses are. Let’s go through an example program:
#include <stdio.h>
int main(int argc, char *argv[])
{
int m = 5;
int n = 7;
printf("value of m -> %d\n", m);
printf("address of m -> %p\n\n", &m);
printf("value of n -> %d\n", n);
printf("address of n -> %p\n", &n);
int *m_addr;
int *n_addr;
printf("\nBefore assigning values to pointers\n\n");
printf("value of pointer m_addr %p\n", m_addr);
printf("value of pointer n_addr %p\n", n_addr);
m_addr = &m;
n_addr = &n;
printf("\nAfter assigning values to pointers\n\n");
printf("value of pointer m_addr %p\n", m_addr);
printf("value of pointer n_addr %p\n", n_addr);
return 0;
}
In the above program, we have an integer m
with a value of 5 and n
with a value of 7. In C, each variable possesses a memory address. When we run this program, we get the following output:
value of m -> 5
address of m -> 0x7ffccce8edd0
value of n -> 7
address of n -> 0x7ffccce8edd4
Variable m
has the memory address 0x7ffccce8edd0
, and for n
, it’s 0x7ffccce8edd4
. An integer is 4 bytes in size, which is why we see a difference of 4 between both memory addresses.
Before assigning values to pointers
value of pointer m_addr 0x75a158039040
value of pointer n_addr 0x7ffccce8eec0
After assigning values to pointers
value of pointer m_addr 0x7ffccce8edd0
value of pointer n_addr 0x7ffccce8edd4
In the C program, we’re first declaring the pointers and displaying their addresses. After assigning the address of variables m
and n
to them, we print the values. As you can see, before assigning the value, it had a different memory address, and after pointing it to the memory addresses of m
and n
, it now shows the addresses of m
and n
.
NOTE: You should never initialize a pointer without assigning a value to it, as it is not a recommended way of using it. You should always initialize it by assigning a value directly, like
int *some_addr = some_var
. Pointers initialized without assigning a value are also called “Wild Pointers.”
Let’s take another example to see how a pointer functions with different things.
#include <stdio.h>
int main(int argc, char *argv[])
{
int numbers[] = {1, 2, 3, 4, 5};
int *p = numbers;
printf("Value at p[0]: %d\n", *p);
p++;
printf("Value at p[1]: %d\n", *p);
p++;
printf("Value of p[2]: %d\n", *p);
return 0;
}
In this program, we have an array numbers
containing five numbers from 1 to 5. We initialize a pointer and assign the address value of the first element of the array, then print it. After incrementing p
and printing again, and repeating the process, the program produces the following output:
➜ c ./a.out
Value at p[0]: 1
Value at p[1]: 2
Value of p[2]: 3
As you can see, as we initialize the pointer, it holds the data of the array element present at the first index, and as we increment p
, it moves to the next indexes.
We can also perform “pointer to pointer” initialization:
#include <stdio.h>
int main(int argc, char *argv[])
{
int n = 10;
int *p1 = &n;
int **p2 = &p1;
printf("Value at var: %d\n", n);
printf("Value at ptr1: %d\n", *p1);
printf("Value at ptr2 (double pointer): %d\n", **p2);
return 0;
}
So what’s happening here, we have an int
variable n
with value 10. We then defined a pointer p1
and assigned address of n
to it. Then we defined another pointer (double pointer) p2
and assigned address of p1
(originally n
). Which prints the below output
➜ c ./a.out
Value at var: 10
Value at ptr1: 10
Value at ptr2 (double pointer): 10