In this tutorial, you will learn the way to manipulate arrays using pointers, i.e how to access elements from an array using pointers, and how to traverse through arrays, etc with the help of some simple examples.
To understand the connection between arrays and pointers, it is always better to know the basics of C pointers and C Arrays beforehand.
Let’s start by examining a simple example that shows how to print the address of each array element in a one-dimensional array.
#include<stdio.h>
int main() {
int arr[5] = {
10,
20,
30,
40,
50
};
for (int i = 0; i < 5; i++) {
printf("The address of element %d in position arr[%d]: %d\n", arr[i], i, & arr[i]);
}
return 0;
}
Output:
The address of element 10 in position arr[0]: 6422016 The address of element 20 in position arr[1]: 6422020 The address of element 30 in position arr[2]: 6422024 The address of element 40 in position arr[3]: 6422028 The address of element 50 in position arr[4]: 6422032
In this example, we have declared an array with 5 elements: 10, 20, 30, 40, and 50. On declaration, the compiler allocates a sufficient amount of memory to store the elements of the array. Here, each element is stored continuously in the memory with a 4 bytes difference between consecutive elements which indicates the byte size of integer. See the below visualization of array elements in memory.
When you observe the image carefully, you could get the answer to the question “ Is the address of array arr
and arr[0]
the same?”. The answer is Yes because array arr always points to the first element which is arr[0]
, so the name of the array is the const pointer that points to the address of the first element. More precisely,
Normally to get the address of array elements we make use of the ampersand (&) symbol. We can also use pointers (*) to get the address of array elements. Let's see how we can modify the above program to get the address of array elements using pointers and produce the same outcome.
#include<stdio.h>
int main() {
int arr[5] = {
10,
20,
30,
40,
50
};
int * p;
p = & arr[0];
for (int i = 0; i < 5; i++) {
printf("The address of element %d in position arr[%d]: %d\n", * p, i, p);
p++;
}
return 0;
}
Output:
The address of element 10 in position arr[0]: 6422016 The address of element 20 in position arr[1]: 6422020 The address of element 30 in position arr[2]: 6422024 The address of element 40 in position arr[3]: 6422028 The address of element 50 in position arr[4]: 6422032
As we know that every element of a pointer has a specific address. Here we have used pointers and increment its address value gradually ( using for loop) to store them. In our example, we have an array arr[5] and a pointer p. We can use them like:
p=&arr[0];
p+1=&arr[1];
p+2=&arr[2];
p+3=&arr[3];
p+4=&arr[4];
p+5=&arr[5];
Similarly, we can use the value stored in it by printing the value of '*p', '*(*p+1)' .*(*p+2) etc.
While using pointers with an array, we need to bear in mind the following points:
Pointers support arithmetic operations, but only addition(increment) and subtraction(decrement). In the case of integers when we increment a number by a unit, the value of the stored variable increases like
4+1=5.
But in the case of pointers, incrementing implies letting the pointer point to the next address location. That is the address value of the cell changes instead of the stored variable's value as shown in the diagram below.
An integer data type needs 4 bytes of memory, so an increment of pointers in these cases will eventually move the pointer by four units. Similarly, float pointers will increase the address value by 4 units, as each of them needs 4 bytes of space for allocation.
When it comes to decrement the pointer will decrease the address value by the bytes of its corresponding datatype. Pointer immediately points to the previous address location.
Since the pointer works on addresses the chance for multiplication and division is completely out of scope.
So far we have discussed pointers that point to single elements of an array. But when a pointer points to a whole array, it is a different concept. In C, the pointer that refers to a whole array is known as a pointer to an array. See below the declaration of a pointer to an array.
datatype (*p)[n]
where data type represents the type of array,
Example:
int (*p)[5]
float (*p)[10]
The key point to be considered is that the round bracket or parentheses around ‘p’ is essential because int *p[5] and int (*p)[5] are different. int *p[5] denotes an array with 5 integer pointers while int (*p)[5] denotes a pointer to an array with 5 integers.
#include<stdio.h>
int main() {
int arr[5];
int * p;
int( * pa)[5];
p = arr;
pa = arr;
printf("Address of p = %d\n", p);
printf("Address of pa = %d\n", pa);
p++;
pa++;
printf("\n...After incrementing p and pa...\n\n");
printf("Address of p = %d\n", p);
printf("Address of pa = %d\n", pa);
return 0;
}
Output:
Address of p = 6422000 Address of pa = 6422000 ...After incrementing p and pa... Address of p = 6422004 Address of pa = 6422020
Working Concept
When you examine the example you can see that p is a pointer that points to the first element of the array arr and hence its base type is a pointer to int. On the other hand, pa is a pointer that refers to the whole array arr and so its base type is a pointer to an array containing 5 integer elements. When the two pointers increments, they work relative to the base type, and consequently the p is incremented by 4 bytes and pa incremented by 20 bytes( 5 x 4 = 20).
So far we have seen the working of pointers on one-dimensional arrays. Now let’s observe how pointers work on a Two - dimensional array. To get a better understanding of two-dimensional arrays refers to our previous tutorial ARRAYS.
We know that a two-dimensional array can be simply visualized as a matrix with rows and columns. But when it comes to the case of memory, a two-dimensional array can be considered as a one-dimensional array with each element itself is a one-dimensional array. This is because in memory everything is stored in a linear manner. The above diagram demonstrates the conceptual view of a two-dimensional array with 2 rows and 3 columns while the below one shows the actual view of a two-dimensional array with 3 rows and 3 columns in the memory.
From the diagram its is clear that in two dimensional array ,
arr[0] == arr : is the zeroth 1 -Dimensional array arr[1] == arr + 1 : is the first 1- Dimensional array
arr[2] == arr +2 : is the second 1- Dimensional array and so on. In general ,
arr[i] == arr + i : represents the ith 1-Dimensional array and so on.
In general ,
arr[i] == arr + i : represents the ith 1-D array .
The following example shows how to print the address of each element in a two-dimensional array.
#include<stdio.h>
int main() {
int arr[3][3]={10,20,30,40,50,60,70,80,90};
int * p;
p = arr;
for (int i = 0; i < 3; i++) {
printf("\n\nThe address of arr[%d]: %d\n", i, p);
for (int j = 0; j < 3; j++) {
printf("The address of element %d in position arr[%d][%d]: %d\n", * p, i, j, p);
p++;
}
}
return 0;
}
Output:
The address of arr[0]: 6421984 The address of element 10 in position arr[0][0]: 6421984 The address of element 20 in position arr[0][1]: 6421988 The address of element 30 in position arr[0][2]: 6421992 The address of arr[1]: 6421996 The address of element 40 in position arr[1][0]: 6421996 The address of element 50 in position arr[1][1]: 6422000 The address of element 60 in position arr[1][2]: 6422004 The address of arr[2]: 6422008 The address of element 70 in position arr[2][0]: 6422008 The address of element 80 in position arr[2][1]: 6422012 The address of element 90 in position arr[2][2]: 6422016
In this example to get the address of each element in the two-dimensional array, we use the pointer variable p. So behind the screen how pointer variable p actually works is as follows.
Let our array be arr and (arr + i) denote the ith 1-D array. To get the address we can prefix the dereference operator (*) directly with (arr+i).i.e,
*(arr+i) gives the address of i th 1-D Array.
More concisely,
*(arr + 0) ⇒ the address of 0th 1 - D Array
*(arr + 1) ⇒ the address of 1st 1 - D Array
*(arr + 2) ⇒ the address of 2nd 1 - D Array
Now to access the address of elements in each array, we need to perform pointer arithmetic as follows
*(arr + 0)+0 ⇒ the address of 0th element of 0th 1 - D Array
*(arr + 0)+1 ⇒ the address of 1st element of 0th 1 - D Array
*(arr + 0)+2 ⇒ the address of 2nd element of 0th 1 - D Array
*(arr + 1)+0 ⇒ the address of 0th element of 1st 1 - D Array
*(arr + 1)+1⇒ the address of 1st element of 1st 1 - D Array
*(arr + 1)+2 ⇒ the address of 2nd element of 1st 1 - D Array
This can be generalized as
*(arr + i)+j⇒ the address of jth element of ith 1 - D Array
It is also possible to access the values of each element in the array. This can be achieved by dereferencing *(arr + i)+j . i.e
*(*(arr + i)+j)⇒ the value of jth element of ith 1 - D Array
The above program can be changed as follows.
#include<stdio.h>
int main() {
int arr[3][3]={10,20,30,40,50,60,70,80,90};
for (int i = 0; i < 3; i++) {
printf("\n\nThe address of arr[%d]: %d\n", i, *(arr + i));
for (int j = 0; j < 3; j++) {
printf("The address of element %d in position arr[%d][%d]: %d\n", *( * (arr + i) + j), i, j, *(arr + i) + j);
}
}
return 0;
}
Here instead of using pointer variables, we used the pointer on the array itself to access both address and values.