How does `* ((* arr + (i * 3)) + j)` work when printing a two-dimensional array `arr`?

code:

#include <stdio.h>

int main(void)
{
    int arr[2][3] = {{1,2,3},{4,5,6}};
    int i, j;

    for(i = 0; i < 2; i++)
    {
        for(j = 0; j < 3; j++)
        {
            printf("%d ", *((*arr+(i*3))+j));
        }
        printf("\n");
    }

    return 0;
}

      

I'm surprised how the above code gives the result:

1 2 3   
4 5 6

      

I know what *(arr+i) == arr[i]

, as well as what I should be using arr[i][j]

instead of making things more complicated, but I don't understand how it works *((*arr+(i*3))+j)

.

In my understanding *((*arr+(i*3))+j)

it can be simplified to *((*arr)+(i*3)+j)

as *

(indirection operator) has the biggest advantage here.

So when it i

is zero and j

iterates through, from 0 to 2, the expression is the same as arr[0][j]

that which prints the integers of the first subarray.

My confusion grows when i

it becomes 1. The next three expressions are *((*arr)+(1*3)+0)

, *((*arr)+(1*3)+1)

and *((*arr)+(1*3)+2)

, which can be simplified to arr[0][3]

, arr[0][4]

and arr[0][5]

.

How does it print the last three values?

+3


source to share


3 answers


int arr[2][3] = {{1,2,3},{4,5,6}};

      

In mind:

1 | 2 | 3 | 4 | 5 | 6
each number on an adjacent memory "cell" the size of an int, in this order

      

Second line: i = 1 j = 0



*((*arr+(i*3))+j)) means *((*arr + 3) + 0)-> *({1, 2, 3} + 3) -> *({4, 5, 6}) = 4

      

Keep in mind that is x[n]

equivalent *(x + n)

regardless of x

or n

. (This also means, which is arr[1]

equivalent *(arr + 1)

, *(1 + arr)

and therefore 1[arr]

, which I find amusing)

Here arr[1][0]

: x

is arr[1]

and n

is 0

, therefore the first equivalence: The *(arr[1] + 0)


second x

is equal arr

and n

equal 1

, therefore *(*(arr + 1) + 0)

.
Finally arr + 1

means address in arr + sizeof(*arr)

, which means: is (arr + 1)

equivalent (*arr + 3)

because there *arr

is arr[0]

, which is of typeint[3]

+3


source


The C language stores multidimensional arrays in so-called row order, so when you declare int arr[2][3]

, memory is actually laid out with the array elements occurring next to each other in memory in this sequence:

arr[0][0] arr[0][1] arr[0][2] arr[1][0] arr[1][1] arr[1][2]

      



This has several implications that are useful to know:

  • arr[1]

    acts like a pointer to a one-dimensional array. how it happens when you declare int **arr;

    .
  • The initializers in your initialization list are copied to memory locations in exactly the order in which you list them.
+3


source


The array is stored in your memory, for example:

_____ _____  _____  _____  _____  _____  
| 1 | | 2 |  | 3 |  | 4 |  | 5 |  | 6 |
----- -----  -----  -----  -----  -----

      

So, even though it is stored in a two-dimensional array, it infects memory allocation at compile time. When you write [1] [1], the compiler refers to the position (1 * (no of columns) + 1) in front, that is, 4 positions from the beginning.

See http://www.fredosaurus.com/notes-cpp/arrayptr/23two-dim-array-memory-layout.html

0


source







All Articles