What's in a name?

In C, pointers and arrays are closely related concepts. In fact, arrays in C are essentially a contiguous block of memory, and the name of the array often decays into a pointer to the first element. This is why you can use pointer notation to access array elements.

Let's go through an example with well-commented code:

#include <stdio.h>

int main() {
    // Declare an array of integers
    int myArray[5] = {10, 20, 30, 40, 50};

    // Declare a pointer to an integer and initialize it with the address of the first element of the array
    int *ptr = myArray;

    // Access array elements using array notation
    printf("Using array notation:\n");
    for (int i = 0; i < 5; ++i) {
        printf("myArray[%d] = %d\n", i, myArray[i]);
    }

    // Access array elements using pointer notation with bracket syntax
    printf("\nUsing pointer notation:\n");
    for (int i = 0; i < 5; ++i) {
        // The following two lines are equivalent
        printf("*(ptr + %d) = %d\n", i, *(ptr + i));
        printf("ptr[%d] = %d\n", i, ptr[i]);
    }

    return 0;
}

In this example:

  1. We declare an array myArray of integers with five elements.

  2. We declare a pointer to an integer ptr and initialize it with the address of the first element of myArray.

  3. We use a loop to print the elements of myArray using array notation (myArray[i]).

  4. We use another loop to print the elements of myArray using pointer notation with bracket syntax (ptr[i] is equivalent to *(ptr + i)).

In C, ptr[i] is equivalent to *(ptr + i), so you can use either notation to access array elements through a pointer. The bracket notation provides a convenient and readable way to work with pointers like arrays.

In C, a multidimensional array is essentially an array of arrays. The name of a multidimensional array, when used in an expression, represents the address of its first element. Let's go through an example with a two-dimensional array:

#include <stdio.h>

int main() {
    // Declare a 2D array of integers
    int myArray[3][4] = {
        {10, 20, 30, 40},
        {50, 60, 70, 80},
        {90, 100, 110, 120}
    };

    // Declare a pointer to an array of integers and initialize it with the address of the first row of the 2D array
    int (*ptr)[4] = myArray; // pointer to an array of 4 integers

    // Access 2D array elements using array notation
    printf("Using array notation:\n");
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 4; ++j) {
            printf("myArray[%d][%d] = %d\n", i, j, myArray[i][j]);
        }
    }

    // Access 2D array elements using pointer notation with bracket syntax
    printf("\nUsing pointer notation:\n");
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 4; ++j) {
            // The following two lines are equivalent
            printf("ptr[%d][%d] = %d\n", i, j, ptr[i][j]);
            printf("*(*(ptr + %d) + %d) = %d\n", i, j, *(*(ptr + i) + j));
        }
    }

    return 0;
}

The expression ptr[i][j] can be equivalently expressed using pointer arithmetic as *(*(ptr + i) + j). Let's break down the equivalence:

  1. ptr[i]: This expression represents the ith row of the 2D array. It's equivalent to *(ptr + i) because the name of the array ptr by itself is a pointer to the first row, and adding i moves the pointer to the ith row.

  2. ptr[i][j]: This expression further accesses the jth element in the ith row of the 2D array. It's equivalent to *(*(ptr + i) + j) because *(ptr + i) gives the address of the ith row, and adding j moves to the jth element in that row.

So, in summary, ptr[i][j] is equivalent to *(*(ptr + i) + j) in terms of pointer arithmetic.

ptr is not a double-pointer. It is a pointer to an array of integers (specifically, an array of 4 integers). The type of ptr is int (*)[4].

A double-pointer in C would be a pointer that points to another pointer. In the context of a 2D array, a double pointer could be used to point to an array of pointers, where each pointer points to a row of the 2D array. Here's an example:

#include <stdio.h>

int main() {
    // Declare a 2D array of integers
    int myArray[3][4] = {
        {10, 20, 30, 40},
        {50, 60, 70, 80},
        {90, 100, 110, 120}
    };

    // Declare a double pointer to int and initialize it with the address of the first row of the 2D array
    int **ptr = (int **)myArray; // casting to int**

    // Access 2D array elements using double pointer notation
    printf("Using double pointer notation:\n");
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 4; ++j) {
            printf("ptr[%d][%d] = %d\n", i, j, ptr[i][j]);
        }
    }

    return 0;
}

In this example, ptr is a double-pointer (int **) because it points to an array of pointers, and each of those pointers, in turn, points to a row of the 2D array.