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?

3 Answers 3

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].

Sign up to request clarification or add additional context in comments.

14 Comments

"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?
@BiggusDickus101 The expression arr + i has the type T ( * )[N]. So dereferencing the pointer you will get an object of the type T[N].
@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.
@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].
@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 *.
|
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.

4 Comments

The first method you've written is the easy way out. I wish to access the array elements solely using pointers.
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)?
According to this answer to another question, the expression *((type *)arr + i * 5 + j) may invoke undefined behavior, depending on how you interpret the standard.
@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.
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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.