The relationship between arrays and pointers in C
This post takes a look at the relationship between arrays and pointers in the C programming language.
Background
The C programming language (2nd edition) emphasizes the relationship between pointers and arrays in the C programming language by dedicating the fifth chapter to covering both arrays and pointers at the same time.
The chapter opens by mentioning that both arrays and pointers are closely related, and how many operations that work on one also work on the other. For example pointer arithmetic and subscript notation can be used with both arrays and pointers. This has been an important realization in my journey to learning C, and I'd like to share what I learnt for myself and for others.
Arithmetic
Pointer arithmetic and arrays are two intertwined concepts in C.
When given a pointer to the first element of an array, we can traverse
to the next memory location using pointer arithmetic. The next memory
location happens to be the next element in the array. The ++
operator can move a pointer to the next memory location, or in the case
of an array pointer, to the next element in the array. We can call the
++
operator repeatedly to traverse the entire array from
start to finish.
The following example focuses primarily on the ++
operator but we could also use the --
operator to traverse
backwards through an array as well. Similarly, we could use the p +
<n>
and p - <n>
operators to obtain a
pointer to the nth element of an array in either direction. That goes to
show how useful pointer arithmetic can be when used with arrays.
But for now let's take a look at how we would traverse an array with a
pointer and the ++
operator. An important realization to
have is that we don't need to know the size of an array in order to
traverse through an array, although ideally, we would have an element in
an array that would indicate when an array ends – similar to a NULL byte
for char arrays:
#include <stdio.h>
#include <stdlib.h>
int
(void)
main{
int numbers[] = {50,20,70};
int *p = &numbers[0];
for (int i = 0; i < 3; i++)
{
("element: %d\n", *p++);
printf}
return (EXIT_SUCCESS);
}
Subscript
In a similar light, we can use the subscript operator to access either
the nth element of an array or the nth memory
location relative to the current memory location of a pointer.
When we reference an array with the subscript arr[4]
we're
accessing the fifth element of an array, and when we do the same for a
pointer (ptr[4]
) we're accessing the fifth memory location
relative to the current memory location of a pointer.
We can also write to the nth element of an array using the subscript operator, and we can do the same with a pointer and the subscript operator as well. The following example writes five elements to an array and for the pointer writes to five memory locations – with each one being adjacent to the other. They're almost indistinguishable from each other:
#include <stdio.h>
#include <stdlib.h>
int
(void)
main{
int *pnumbers = calloc(5, sizeof(int));
int numbers[5] = {};
for (int i = 0; i < 5; i++)
{
/* write */
[i] = i;
pnumbers[i] = i;
numbers/* read */
("pnumbers[%d] => %d\n", i, pnumbers[i]);
printf("numbers[%d] => %d\n", i, numbers[i]);
printf}
(pnumbers);
freereturn (EXIT_SUCCESS);
}
Functions
In the C language – arguments to functions are passed by value. And when we pass an array to a function, it is said to "decay" into a pointer. This means that the argument becomes a pointer to the first element of the array. But it doesn't have to be the first element, it could be the third, or second, or any other element in the array. By default a pointer to the the first element is passed to the function.
The following example illustrates this point by passing an array to a
function named walk
and within the walk
function we receive an int pointer to the first element of the array from
the caller's scope. The function then traverses the array and prints each
element to standard output:
#include <stdio.h>
#include <stdlib.h>
static void walk(int *p);
int main(void)
{
int numbers[] = {50,20,70};
(numbers);
walkreturn (EXIT_SUCCESS);
}
static void
(int *p)
walk{
for (int i = 0; i < 3; i++)
{
("element: %d\n", *p++);
printf}
}
Conclusion
We can conclude that arrays and pointers are closely related to C, and that they can be used interchangeably in many cases. The similarities have a lot to do with both arrays and pointers being stored in contiguous memory locations, and that pointer arithmetic and the subscript operator can be used with both arrays and pointers.