| Author |
Message |
|
|
Posted: Jun 15, 2012 - 02:41 AM |
|

Joined: May 09, 2009
Posts: 113
|
|
I have a question regarding two-dimensional arrays.
When trying to access a two-dimensional array with pointer arithmetic the following is used:
*(*(array_name + row) + column)
Example:
Code:
int B[2][2] = {4, 5, 6, 7};
printf("B = #p\n", B); // address of B[0][0]
printf("&B = #p\n", &B); // address of B[0][0]
printf("B+1 = #p\n", B+1); // address of B[1][0]
printf("B[0][0] = #d\n", B[0][0]); // content of B[0][0] = 4
printf("B[0] = #p\n", B[0]); // address of B[0][0]
printf("*B = #p\n", *B); // address of B[0][0]
printf("**B = #d\n", **B); // content of B[0][0] = 4
printf("**(B+1) = #d\n", **(B+1)); // content of B[1][0] = 6
printf("**B+1 = #d\n", **B+1); // content of B[0][1] = 5
printf("**B+3 = #d\n", **B+3); // content of B[1][1] = 7
# = % in above code to get around the Bad Request Error
I have a hard time understanding this.
Why does it take (2) de-references to get the content of the specific array element?
Can someone explain how this works? |
Last edited by westco on Jun 15, 2012 - 07:45 AM; edited 9 times in total
|
| |
|
|
|
|
|
Posted: Jun 15, 2012 - 04:42 AM |
|

Joined: Apr 28, 2012
Posts: 70
|
|
We have to see the declaration of array_name to make sense of it.
My guess: array_name is declared as "something **array_name" |
|
|
| |
|
|
|
|
|
Posted: Jun 15, 2012 - 04:57 AM |
|

Joined: Dec 18, 2001
Posts: 4717
|
|
|
Quote:
*(*(array_name + row) + column)
That's awful code and invalid, I say. |
|
|
| |
|
|
|
|
|
Posted: Jun 15, 2012 - 05:30 AM |
|

Joined: Mar 09, 2012
Posts: 1452
Location: North Carolina, USA
|
|
|
stevech wrote:
Quote:
*(*(array_name + row) + column)
That's awful code and invalid, I say.
I don't like it either, but it looks valid to me. (Assuming array_name is a **) |
|
|
| |
|
|
|
|
|
Posted: Jun 15, 2012 - 05:41 AM |
|

Joined: Mar 09, 2012
Posts: 1452
Location: North Carolina, USA
|
|
|
westco wrote:
I have a question regarding two-dimensional arrays.
When trying to access a two-dimensional array with pointer arithmetic the following is used:
*(*(array_name + row) + column)
I have a hard time understanding this.
Why does it take (2) de-references to get the content of the specific array element?
Can someone explain how this works?
Rather than explain how that works, I'll tell you how I'd write it:
Code:
array_name[row][column]
I would have to see the array declaration and do some testing to be sure that's the same, but I think it will work. |
|
|
| |
|
|
|
|
|
Posted: Jun 15, 2012 - 06:16 AM |
|

Joined: Nov 09, 2011
Posts: 402
|
|
It's one of these weirdo C-isms. Let's say you have an array declared thusly:
Code:
int z[10][4];
This declares z to be a 10 row array. Each row of this array is an array of 4 ints.
Dereferencing z once gives you a value that's one of the rows of z, so it's one of the 4 element int arrays, or equivalently an int pointer (recall that in C, int pointers and int arrays are sorta interchangable). This is how we assign zp to the 2nd row of z:
Code:
int z[10][4];
int *zp = *(z + 2);
Since zp is now a regular garden variety pointer, dereferencing zp gives you an int. Thus, to get the third int value in the second row of z we do:
Code:
int z[10][4];
int *zp = *(z + 2);
int y = *(zp + 3);
We can combine the two dereferences in a single statement:
Code:
int z[10][4];
int y = *(*(z + 2) + 3);
- S
ps: observant folks will note that I'm assigning y from an uninitialised value. |
|
|
| |
|
|
|
|
|
Posted: Jun 15, 2012 - 06:29 AM |
|

Joined: Nov 17, 2004
Posts: 13849
Location: Vancouver, BC
|
|
|
Quote:
I would have to see the array declaration and do some testing to be sure that's the same, but I think it will work.
I don't think so. array_name is an address of the start of the array, (array_name + row) is the address of an element of the array. *(array_name + row) is the value of the array element. In order for adding column to that value to make sense, it would have to be another pointer, and therefore array_name must be an array of pointers to arrays, not a straight two dimensional array.
In order to access a two dimensional array with pointer arithmetic, you need to know the size of the array (or at least the number of columns). |
_________________ Regards,
Steve A.
The Board helps those that help themselves.
|
| |
|
|
|
|
|
Posted: Jun 15, 2012 - 07:46 AM |
|

Joined: May 09, 2009
Posts: 113
|
|
| I added an example to the original post. |
|
|
| |
|
|
|
|
|
Posted: Jun 15, 2012 - 08:01 AM |
|

Joined: Nov 09, 2011
Posts: 402
|
|
|
westco wrote:
Code:
int B[2][2] = {4, 5, 6, 7};
printf("B = #p\n", B); // address of B[0][0]
printf("&B = #p\n", &B); // address of B[0][0]
printf("B+1 = #p\n", B+1); // address of B[1][0]
printf("B[0][0] = #d\n", B[0][0]); // content of B[0][0] = 4
printf("B[0] = #p\n", B[0]); // address of B[0][0]
printf("*B = #p\n", *B); // address of B[0][0]
printf("**B = #d\n", **B); // content of B[0][0] = 4
printf("**(B+1) = #d\n", **(B+1)); // content of B[1][0] = 6
printf("**B+1 = #d\n", **B+1); // content of B[0][1] = 5
printf("**B+3 = #d\n", **B+3); // content of B[1][1] = 7
The comments in the last 2 examples aren't right. What's happening is that the "*" dereference operator has higher precedence than the "+" operator. So,
Code:
**B+1
is the same value as
Code:
(**B) + 1
which is the same value as B[0][0] + 1
- S |
|
|
| |
|
|
|
|
|
Posted: Jun 15, 2012 - 08:59 AM |
|

Joined: Mar 09, 2012
Posts: 1452
Location: North Carolina, USA
|
|
|
Koshchi wrote:
Quote:
I would have to see the array declaration and do some testing to be sure that's the same, but I think it will work.
I don't think so. array_name is an address of the start of the array, (array_name + row) is the address of an element of the array. *(array_name + row) is the value of the array element. In order for adding column to that value to make sense, it would have to be another pointer, and therefore array_name must be an array of pointers to arrays, not a straight two dimensional array.
Who said it was a two-dimensional array ? In order to make sense out of the posted code, I assumed the array was declared a **. The posted notation is a stupid way to do it anyway.
And like I said, I would like to see the array declaration at hand. Now he's thrown in a [][] declaration, which makes the posted notation even more stupid - and my suggestion will still work. |
|
|
| |
|
|
|
|
|
Posted: Jun 15, 2012 - 09:13 AM |
|


Joined: Mar 27, 2002
Posts: 18585
Location: Lund, Sweden
|
|
|
ChaunceyGardiner wrote:
Who said it was a two-dimensional array ?
In the very first post, perhaps edited in, westco wrote:
I have a question regarding two-dimensional arrays.
[...]
Code:
int B[2][2] = {4, 5, 6, 7};
|
|
|
| |
|
|
|
|
|
Posted: Jun 15, 2012 - 09:50 AM |
|

Joined: Mar 09, 2012
Posts: 1452
Location: North Carolina, USA
|
|
|
JohanEkdahl wrote:
ChaunceyGardiner wrote:
Who said it was a two-dimensional array ?
In the very first post, perhaps edited in, westco wrote:
I have a question regarding two-dimensional arrays.
[...]
Code:
int B[2][2] = {4, 5, 6, 7};
If you read the rest of the post of mine that you quoted you should be able to deduce that he did indeed throw that in later. And my suggestion should work for that too, so... |
|
|
| |
|
|
|
|
|
Posted: Jun 15, 2012 - 11:33 AM |
|


Joined: Jul 18, 2005
Posts: 62354
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
Not sure what your intention here is exactly but does it help to know that if you use:
Code:
int (*foo)[2] = (int (*)[2])B;
then you can just use the same array notation with foo. That is:
Code:
foo[1][1] = 9;
This allows you to pass around a multi-dim array pointer then just continue to access it as a multi-dim array. For example:
Code:
void process(int (*alsodata)[2][2]) {
uint8_t i,j,k;
for (i=0; i<3; i++) {
for(j=0; j<2; j++) {
for(k=0; k<2; k++) {
alsodata[i][j][k] += 1;
}
}
}
}
int main(void) {
int data[3][2][2] = {
{{4,7}, {5,3}},
{{2,9}, {4,8}},
{{5,6}, {6,1}},
};
process((int (*)[2][2])data);
}
Of course process() could just as easily be:
Code:
void process(int alsodata[3][2][2]) {
uint8_t i,j,k;
for (i=0; i<3; i++) {
for(j=0; j<2; j++) {
for(k=0; k<2; k++) {
alsodata[i][j][k] += 1;
}
}
}
}
but if you just have an int * pointer and want to apply a multi-dim interpretation onto it the former is the way to go:
Code:
void process(int * p) {
int (*alsodata)[2][2] = (int (*)[2][2])p;
uint8_t i,j,k;
for (i=0; i<3; i++) {
for(j=0; j<2; j++) {
for(k=0; k<2; k++) {
alsodata[i][j][k] += 1;
}
}
}
}
int main(void) {
int data[3][2][2] = {
{{4,7}, {5,3}},
{{2,9}, {4,8}},
{{5,6}, {6,1}},
};
process((int *)data);
}
in which alldata reinterprets the plain int pointer that was passed. |
_________________
|
| |
|
|
|
|
|
Posted: Jun 15, 2012 - 04:27 PM |
|

Joined: May 09, 2009
Posts: 113
|
|
Thanks for all the posts on this.
I am not really interested in knowing all the other ways of doing this. I want to know how the original posts arithmetic pointer's work to access a two-dimensional array.
Does anybody understand the example code in the original post?
Is this true: *(*(array_name + row) + column)
Why does one need two de-references to access the content of the array element? |
|
|
| |
|
|
|
|
|
Posted: Jun 15, 2012 - 05:21 PM |
|

Joined: Aug 07, 2007
Posts: 1477
Location: Czech
|
|
|
Code:
x = *(*(array_name + row) + column)
x = *(array_name + row) + column
I did some tests and I am a little confused.
How is it possible that both lines give the same (and right) result ? |
|
|
| |
|
|
|
|
|
Posted: Jun 15, 2012 - 07:15 PM |
|

Joined: Mar 09, 2012
Posts: 1452
Location: North Carolina, USA
|
|
|
westco wrote:
Is this true: *(*(array_name + row) + column)
Not sure what you mean when you say "is this true" but...
Code:
A = array_name;
B = *(A + row); // A must be a pointer or array for this to work
C = *(B + column); // B must be a pointer or array for this to work
So for you to be able to use this to access C as you do in your example, it follows that A must be a |pointer to or array of| some |pointers to or arrays of| some type. |
|
|
| |
|
|
|
|
|
Posted: Jun 16, 2012 - 01:41 AM |
|


Joined: Oct 30, 2002
Posts: 5720
Location: The Netherlands
|
|
|
Quote:
Is this true: *(*(array_name + row) + column)
Yes. See here
The a[b] notation is just syntactic sugar for *(a+b).
So... a[row][col]=(*(a+row))[col]=*(*(a+row)+col))
And... for laughs:
Code:
int arr[10];
(arr+2)[3]=5["abcdefg"];
Is perfectly legal and working C  |
|
|
| |
|
|
|
|
|
Posted: Jun 16, 2012 - 07:51 AM |
|

Joined: Apr 28, 2012
Posts: 70
|
|
|
Visovian wrote:
Code:
x = *(*(array_name + row) + column)
x = *(array_name + row) + column
I did some tests and I am a little confused.
How is it possible that both lines give the same (and right) result ?
No, those lines are not equivalent. If array_name is a double-array or pointer-to-pointer, the type of the first line is element, but the type of the second line is pointer. The only case where those lines are equivalent would be where "x" and "*x" have the same value, which certainly is possible if the item at address X happens to also have the value X.
The double-array also makes sense if you pick it apart one step at a time:
Code:
unsigned int foo[3][7] = ...;
This reads, inside-out, right-before-left, as "foo is an array of 3 arrays of 7 unsigned ints."
Thus, once you dereference it once, you end up with "array of 7 unsigned ints." When you dereference it a second time, you end up with "unsigned int."
Generally, C declarations are read inside-out, first right, then left.
The main trick here is that you peel off only one thing at a time, both when writing the declaration, and when reading it, and when using it. |
|
|
| |
|
|
|
|
|
Posted: Jun 16, 2012 - 04:13 PM |
|

Joined: Aug 07, 2007
Posts: 1477
Location: Czech
|
|
|
Quote:
The only case where those lines are equivalent would be where "x" and "*x" have the same value,
You are right.
It was the case, thanks. |
|
|
| |
|
|
|
|
|