In C, arrays and pointers are closely related because an array name acts like a constant pointer to its first element. Therefore, arr and &arr[0] represent the same address.
- The array name can be assigned to a pointer of the same type, allowing the array elements to be accessed using pointer notation.
- Although arr behaves like a pointer to the first element, it is not a pointer variable and its address cannot be changed.
#include <stdio.h>
int main() {
// Declare an array
int arr[3] = { 5, 10, 15 };
// Access first element using index
printf("%d\n", arr[0]);
// Access first element using pointer
printf("%d\n", *arr);
return 0;
}
Output
5 5
Not only that, as the array elements are stored continuously, we can pointer arithmetic operations such as ++, --, +, and - of integers on pointer to move between array elements.
Traversing Array Using Pointer to First Element
#include <stdio.h>
int main() {
int arr[5] = { 1, 2, 3, 4, 5 };
int n = sizeof(arr) / sizeof(arr[0]);
// Defining the pointer to first element of array
int* ptr = &arr[0];
// Traversing array using pointer arithmetic
for (int i = 0; i < 5; i++)
printf("%d ",ptr[i]);
return 0;
}
Output
1 2 3 4 5
Passing Array to Function
There are multiple syntax to pass the arrays to function in C, but no matter what syntax we use, arrays are always passed to function using pointers. This phenomenon is called array decay.
#include <stdio.h>
void f1(int arr[3]) {
printf("Size in f1: %lu bytes\n", sizeof(arr));
}
void f2(int arr[]) {
printf("Size in f2: %lu bytes\n", sizeof(arr));
}
void f3(int *arr) {
printf("Size in f3: %lu bytes\n", sizeof(arr));
}
int main() {
int arr[3] = { 1, 2, 3 };
printf("Size in main(): %lu bytes\n", sizeof(arr));
f1(arr);
f2(arr);
f3(arr);
return 0;
}
Output
Size in main(): 12 bytes Size in f1: 8 bytes Size in f2: 8 bytes Size in f3: 8 bytes
This concept is not limited to the one-dimensional array, we can refer to a multidimensional array element as well using pointers. Moreover, it gets more interesting in multidimensional arrays.
Pointers and 2D Arrays
The elements of a two-dimensional array can be accessed using either array indexing or pointer notation. In pointer notation, any element arr[i][j] can be accessed through pointer expressions.
- The first subscript (i) specifies the row, while the second subscript (j) specifies the column.
- Using pointer notation, arr[i][j] is equivalent to *(*(arr + i) + j).
Now we'll see how this expression can be derived. Let's take a two-dimensional array arr[3][4]:Â
int arr[3][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} };
A 2-D array is stored linearly in memory rather than as actual rows and columns. In C, the elements are stored in row-major order, where all elements of one row are stored contiguously before the elements of the next row.

Each row can be considered as a 1-D array, so a two-dimensional array can be considered as a collection of one-dimensional arrays that are placed one after another.
- The array name arr is a constant pointer that points to the 0th (first) 1-D array (row) and initially stores its starting address (e.g., 5000).
- Since arr is a pointer to an array of 4 integers, pointer arithmetic moves by the size of an entire row, not by a single element.
- Therefore, arr + 1 points to the 1st row (address 5016) and arr + 2 points to the 2nd row (address 5032).
- In general, arr points to the first row, arr + 1 to the second row, and arr + 2 to the third row of the 2-D array.

In general, we can write
(arr + i ) points to ith 1-D array
- arr + i points to the ith row of the 2-D array.
- Dereferencing it, *(arr + i), gives the base address of the ith row, which is equivalent to arr[i].
- Adding j, i.e., *(arr + i) + j, points to the jth element of the ith row.
- Dereferencing it again gives the actual element: *(*(arr + i) + j), which is equivalent to arr[i][j].
Example that uses pointers to traverse the 2D array:
#include <stdio.h>
int main() {
int arr[3][4] = { {1, 2, 3, 4}, {5, 6, 7, 8},
{9, 10, 11, 12} };
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++)
// using pointer notation for 2d array
printf("%d ", *(*(arr + i) + j));
printf("\n");
}
return 0;
}
Output
1 2 3 4 5 6 7 8 9 10 11 12
For passing 2d array to function using pointer, refer to this article - Pass a 2D array as a parameter
Pointers and 3D Arrays
A three-dimensional array uses three subscripts to represent the depth, row, and column. Like 2-D arrays, its elements can also be accessed using pointer notation.
- arr[i] represents the base address of the ith 2-D array.
- arr[i][j] represents the base address of the jth 1-D array within the ith 2-D array.
- The element arr[i][j][k] can be accessed using the pointer expression *(*(*(arr + i) + j) + k).

Example that uses pointers to traverse the 3D array
#include <stdio.h>
int main() {
int arr[2][3][2] = {{{5, 10}, {6, 11}, {7, 12}},
{{20, 30}, {21, 31}, {22, 32}}};
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
for (int k = 0; k < 2; k++)
// Accessing using pointer notation
printf("%d ", *(*(*(arr + i) + j) + k));
printf("\n");
}
printf("\n");
}
return 0;
}
Output
5 10 6 11 7 12 20 30 21 31 22 32
The following figure shows how the 3-D array used in the above program is stored in memory.Â

Related Article: Pass a 3D Array to a Function