Forum Menu




 


Log in Problems?
New User? Sign Up!
AVR Freaks Forum Index

Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Author Message
westco
PostPosted: Jun 15, 2012 - 02:41 AM
Hangaround


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
 
 View user's profile Send private message  
Reply with quote Back to top
jwatte
PostPosted: Jun 15, 2012 - 04:42 AM
Wannabe


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"
 
 View user's profile Send private message  
Reply with quote Back to top
stevech
PostPosted: Jun 15, 2012 - 04:57 AM
Raving lunatic


Joined: Dec 18, 2001
Posts: 4717


Quote:
*(*(array_name + row) + column)


That's awful code and invalid, I say.
 
 View user's profile Send private message  
Reply with quote Back to top
ChaunceyGardiner
PostPosted: Jun 15, 2012 - 05:30 AM
Posting Freak


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 **)
 
 View user's profile Send private message  
Reply with quote Back to top
ChaunceyGardiner
PostPosted: Jun 15, 2012 - 05:41 AM
Posting Freak


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.
 
 View user's profile Send private message  
Reply with quote Back to top
mnehpets
PostPosted: Jun 15, 2012 - 06:16 AM
Hangaround


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.
 
 View user's profile Send private message  
Reply with quote Back to top
Koshchi
PostPosted: Jun 15, 2012 - 06:29 AM
10k+ Postman


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.
 
 View user's profile Send private message  
Reply with quote Back to top
westco
PostPosted: Jun 15, 2012 - 07:46 AM
Hangaround


Joined: May 09, 2009
Posts: 113


I added an example to the original post.
 
 View user's profile Send private message  
Reply with quote Back to top
mnehpets
PostPosted: Jun 15, 2012 - 08:01 AM
Hangaround


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
 
 View user's profile Send private message  
Reply with quote Back to top
ChaunceyGardiner
PostPosted: Jun 15, 2012 - 08:59 AM
Posting Freak


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.
 
 View user's profile Send private message  
Reply with quote Back to top
JohanEkdahl
PostPosted: Jun 15, 2012 - 09:13 AM
10k+ Postman


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};
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
ChaunceyGardiner
PostPosted: Jun 15, 2012 - 09:50 AM
Posting Freak


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...
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Jun 15, 2012 - 11:33 AM
10k+ Postman


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.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
westco
PostPosted: Jun 15, 2012 - 04:27 PM
Hangaround


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?
 
 View user's profile Send private message  
Reply with quote Back to top
Visovian
PostPosted: Jun 15, 2012 - 05:21 PM
Posting Freak


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 ?
 
 View user's profile Send private message  
Reply with quote Back to top
ChaunceyGardiner
PostPosted: Jun 15, 2012 - 07:15 PM
Posting Freak


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.
 
 View user's profile Send private message  
Reply with quote Back to top
jayjay1974
PostPosted: Jun 16, 2012 - 01:41 AM
Raving lunatic


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 Wink
 
 View user's profile Send private message  
Reply with quote Back to top
jwatte
PostPosted: Jun 16, 2012 - 07:51 AM
Wannabe


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.
 
 View user's profile Send private message  
Reply with quote Back to top
Visovian
PostPosted: Jun 16, 2012 - 04:13 PM
Posting Freak


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.
 
 View user's profile Send private message  
Reply with quote Back to top
Display posts from previous:     
Jump to:  
All times are GMT + 1 Hour
Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Powered by PNphpBB2 © 2003-2006 The PNphpBB Group
Credits