2

I was going through the passage pertaining to the access of individual elements of a 2D array using pointers.

It suggests the following mechanism to access the ith row's jth element of the 2D array arr[5][5]:

*(*(arr+i)+j)

From my cursory understanding of pointers, I am given to understand that the name of the array yields the address of the 0th element of the 0th row, and that any integral increment to the array will yield the base address of the next row. All's fine till this juncture, I suppose.

However, what I fail to understand is the relevance of the indirection (*) operator within the following snippet:

*(arr+i)

How is the indirection operator in this case relevant? Since the name of the array itself yields the base address of the 0th row, adding any integral number to it entails it to point to the base element of the next row. In that case, the following snippet yields the address of the ith row:

(arr+i)

And the addition of j warrants the pointer to point to the jth element of the said row.

However, in the following snippet:

*(arr+i)

Wouldn't the addition of the indirection operator cause it to yield the ith element of the row, as opposed to the address of the base element of the ith row?

Should not the following be the code to access the ith row's jth element?

*((arr+i)+j)

In the aforementioned case, incrementing arr i times will entail the code fragment (arr+i) to point to the base address of the ith row, and then the addition of j will entail the address of the ith row's jth element, and then the indirection operator (*) would yield the element that the specific address holds, wouldn't it?

Is my reasoning satisfactory?

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335

3 Answers3

1

From my cursory understanding of pointers, I am given to understand that the name of the array yields the address of the 0th element of the 0th row, and that any integral increment to the array will yield the base address of the next row. All's fine till this juncture, I suppose.

It is not exactly how you think.

An array designator used in an expression is implicitly converted (with rare exceptions) to a pointer to its first element.

If you have a two-dimensional array like for example

T arr[M][N];

(where T is some type specifier) then the array designator arr is converted to a pointer of the type T ( * )[N] that points to the first element of the array arr[0] having the type T[N].

Of course the value of the pointer is equal to the value of the address of the first element arr[0][0] of the type T.

So let's consider the expression

*(*(arr+i)+j)

In this expression the array designator arr is converted to pointer to the first element of the array. That is the expression arr yields the value of the expression &arr[0]. The expression arr + i yields the value &arr[i]. Dereferencing the expression like *( arr + i ) you will get one dimensional array arr[i] that in turn used in the expression *( arr + i ) + j is converted to a pointer to its first element of the type T * that is equivalent to the expression &arr[i][0] . And due to adding the variable j the pointer points to the element &arr[i][j]. Dereferencing this expression like

*(*(arr+i)+j)

that is equivalent to the expression &arr[i][j] you will get the element arr[i][j].

Sreeraj Chundayil
  • 5,548
  • 3
  • 29
  • 68
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • "Dereferencing the expression like *( arr + i ) you will get one dimensional array arr[i]": um, would this not yield the value of the element stored at the 0th position of the ith row as opposed to the one-dimensional array? – LordObnoxious Aug 31 '21 at 17:08
  • 1
    @BiggusDickus101 The expression arr + i has the type T ( * )[N]. So dereferencing the pointer you will get an object of the type T[N]. – Vlad from Moscow Aug 31 '21 at 17:12
  • "So dereferencing the pointer you will get an object of the type T[N]": can you clarify this statement further? I don't follow. – LordObnoxious Aug 31 '21 at 17:38
  • 1
    @LordObnoxious If for example you have a pointer like int x; int *p = &x; then dereferencing the pointer p like *p you will get the object x. – Vlad from Moscow Aug 31 '21 at 19:10
  • Alright. Say, for instance, that there exists a 2D array arr[3][3] which has been initialized with random values. There exists a pointer B to the 2D array. If I were to print the value of B, it would yield the starting address of the first row block of elements, i.e. &arr[0]. Why is it that when I print the value of *B, instead of yielding the value of the element stored in arr[0][0], it still yields the base address of the first row? – LordObnoxious Sep 01 '21 at 10:23
  • 1
    @LordObnoxious The array designator obtained by the expression *B is implicitly converted to pointer to its first element. That is the expression *B yields the array of the type int [3] that in turn is converted to a pointer. If you will write for example printf( "%zu\n", sizeof( *B ) ); you will get the size of an array of the type int[[3]. – Vlad from Moscow Sep 01 '21 at 10:33
  • Makes sense. So, in essence, there exists no difference between B and *B when it points to a 2D array, is it? – LordObnoxious Sep 01 '21 at 10:46
  • 1
    @LordObnoxious You are wrong. The type of B is int ( * )[3]. The type of the expression *B is int[3]. And if (B is used in expressions it is (with rare exceptions) converted to the type int *. – Vlad from Moscow Sep 01 '21 at 10:50
  • "The type of the expression *B is int[3]": if this is the case, why is it that printing this value yields the base address of the row (pointer designator)as opposed to the value of the first element of the row? I printed both B and *B, and yet, both warranted the same result. Is it by design or is something amiss? – LordObnoxious Sep 01 '21 at 11:12
  • @LordObnoxious I already wrote that an array designator is implicitly converted to pointer to its first element. – Vlad from Moscow Sep 01 '21 at 11:19
  • That I understand. What I fail to grasp is why dereferencing B (*B) yields not the value of the base element but the base address. For instance, had a pointer int *P pointed to a simple 1D array titled arr[3], then printing P and *P would have yielded the address of the first element of the array and the value it points to respectively. Why does the same not stand true for a 2D array and the aforementioned example? – LordObnoxious Sep 01 '21 at 12:32
  • @LordObnoxious What value are you going to obtain when using an array?! You could write for example ( *B )[0] to get a value of the first element of the array. – Vlad from Moscow Sep 01 '21 at 12:48
  • I printed the value of (*B)[0], and as you stated, it yielded the value of the first element of the row. Incrementing B and then printing the value of (*B)[0] yielded the zeroth element of the second ray. This works. However, my question still stands: why is it that the values of both B and *B are the same? Why do both return the same value (base address of the zeroth row)? – LordObnoxious Sep 01 '21 at 15:24
  • @LordObnoxious They both return the address of the extent of memory occupied by the array. Ig you have some questions you may ask them here at SO. – Vlad from Moscow Sep 01 '21 at 16:51
0

The ith/jth element should be accessed using

arr[i][j]

but if for some reason you had to do it the hard way it would be

*((type *)arr + i * 5 + j)

where the 5 is the number of columns in the array. The problem with

*((arr+i)+j)

is arr is of the wrong type and things break down. In theory, the following should work but I never tried anything like it:

*((type *)(arr+i)+j)

But from here we are in a position to discuss

*(*(arr+i)+j)

again; I have never tried this; just the rectangular form at the top. But we should be able to understand this. Type of arr is type[][] which is convertible to type[]*; thus it the result of *(arr + i) should be the ith row as type type[] which is convertible to type*; thus we should expect *(*(arr+i)+j) to access the ith row of the jth column. Without the inner deference we would end up with the (i+j)th row instead.

Note that arr must be declared correctly or it's going to interpret it as pointer to pointer rather than pointer to array and do the wrong thing.

Joshua
  • 40,822
  • 8
  • 72
  • 132
  • The first method you've written is the easy way out. I wish to access the array elements solely using pointers. – LordObnoxious Aug 31 '21 at 15:30
  • What is the relevance of the indirection operator in *(arr+i), which itself is a constituent of the larger snippet that goes *(*(arr+i)+j)? Should it simply not be (arr+i) instead of *(arr+i)? – LordObnoxious Aug 31 '21 at 15:32
  • According to [this answer](https://stackoverflow.com/a/43851980/12149471) to another question, the expression `*((type *)arr + i * 5 + j)` may invoke undefined behavior, depending on how you interpret the standard. – Andreas Wenzel Aug 31 '21 at 15:39
  • @AndreasWenzel: The memory layout of array of array is defined to be thus; if for some reason this really invokes undefined behavior on some compilers, adding `volatile` to the pointer cast will make the undefined behavior go away. It has just been pointed out to me a month ago that `volatile` in similar constructs is superstitious and no real compiler breaks the code. – Joshua Aug 31 '21 at 15:41
0
*((arr+i)+j)

The parentheses around (arr+i) are mathematically unnecessary, but they are not enough to switch dimensions from rows to elements. i is for rows, j for elements, and it is a good idea to group them, but it takes *(...).

With *(arr + i + j) it seems obvious that i and j are on the same level.