Re: Multidimensional C arrays as OBJ-C method args: partial
Re: Multidimensional C arrays as OBJ-C method args: partial
- Subject: Re: Multidimensional C arrays as OBJ-C method args: partial
- From: Bill Bumgarner <email@hidden>
- Date: Wed, 2 Jan 2002 18:17:21 -0500
This isn't a limit of objective-c, it is a limitation of the way the code
is written. Likewise, the compiler warning occurs because there is a type
mismatch.
Specific explanation interleaved with the original [extremely well written/
researched] example below.
b.bum
On Wednesday, January 2, 2002, at 05:31 PM, email@hidden.
com wrote:
Date: Wed, 02 Jan 2002 16:28:19 -0600
Subject: Multidimensional C arrays as OBJ-C method args: partial
solution with compiler warning
From: Bob Savage <
>
To: Cocoa-Dev <email@hidden>
.....
int main (int argc, const char * argv[]) {
int i, j;
float simple[3];
float multidimensional[4][3];
In terms of pointers, multidimensional is now effectively an array of
pointers where each pointer points to an array of floats. More below.
......
// compare the size in main to the size from within a method
printf(" (ANSI C understands the size of the multidimensional array
to
be this: %d)\n", (int)sizeof(multidimensional));
ANSI C only knows the size of the multidimensional array because your
declaration explicitly gives the size. Consider this code:
int main() {
float foo[2][2];
float *bar[2];
foo[0][0] = 0.0;
foo[0][1] = 0.1;
foo[1][0] = 1.0;
foo[1][1] = 1.1;
bar[0] = foo[0];
bar[1] = foo[1];
printf("sizeof foo(%d), bar(%d)\n", sizeof(foo), sizeof(bar));
printf("foo: %1.1f, %1.1f, %1.1f, %1.1f\n", foo[0][0], foo[0][1], foo[
1][0], foo[1][1]);
printf("bar: %1.1f, %1.1f, %1.1f, %1.1f\n", bar[0][0], bar[0][1], bar[
1][0], bar[1][1]);
return 0;
}
And the output:
sizeof foo(16), bar(8)
foo: 0.0, 0.1, 1.0, 1.1
bar: 0.0, 0.1, 1.0, 1.1
The sizeof() operator returns different values for the two variables
because it has less type information for the second variable. sizeof()
is a compile time operation-- it has no knowledge of what a pointer
actually points to.
// here I can jump to an arbitrary spot using pointer arithmetic
printf(" The element at [2][1] has a value of %.3f\n",
*(*multidimensional+1)+2);
Like:
printf("foo pointer: %1.1f, %1.1f, %1.1f, %1.1f\n", **foo, *(*foo+1),
*(*foo)+1, *(*foo+1)+1);
Yields:
foo pointer: 0.0, 0.1, 1.0, 1.1
// the following line behaves as expected, but generates a compiler
warning:
// "passing arg 1 of
'setFloatValueByTotallingArrayPointer:ofSize:andStride:' from incompatible
pointer type"
//
[aTester setFloatValueByTotalingArrayPointer:multidimensional ofSize:
4
andStride:3 ];
The compiler warning is because the method declaration indicates that it
is taking a (float *), not a (float *)[] or a float[][].
.... useful declarations deleted ....
....
-(void)setFloatValueByTotalingArrayPointer:(float *)theArray
ofSize:(int)size andStride:(int)stride {
int i, j;
int s = sizeof(theArray);
float total1, total2;
// array size is even further disguised
printf("\tInside
-setFloatValueByTotalingArrayPointer:ofSize:andStride:\n");
printf("\treceived array with size %d\n", s);
sizeof(theArray) will be 4 (assuming a 32 bit machine) because the
compiler *only* knows that it has received a pointer to an array of floats
-- it has no way of knowing anything about what is on the other side of
the pointer.
// the whole thing manually
total1 = 0;
for (i = 0; i < size; i++) {
f = 0; // reset the value before totaling
for (j = 0; j < stride; j++) {
printf("\t\tvalue of the array at slot [%d] = '%.3f'\n", i,
theArray[i*stride+j]);
f+=theArray[i*stride+j];
And here, you have effectively flattened the multidimensional array into a
single flat array... This makes the assumption that an array declaration
of, say, float f[5][6] will effectively turn into an array of consecutive
floats fronted by an array of pointers into that array of floats.... which
appears to be the case:
printf("sizeof foo(%d), bar(%d)\n", sizeof(foo), sizeof(bar));
printf("foo: %1.1f, %1.1f, %1.1f, %1.1f\n", foo[0][0], foo[0][1], foo[
1][0], foo[1][1]);
printf("bar: %1.1f, %1.1f, %1.1f, %1.1f\n", bar[0][0], bar[0][1], bar[
1][0], bar[1][1]);
printf("foo pointer: %1.1f, %1.1f, %1.1f, %1.1f\n", **foo, *(*foo+1),
*(*foo)+1, *(*foo+1)+1);
printf("foo pointer: %1.1f, %1.1f, %1.1f, %1.1f\n", foo[0][0],foo[0][1]
,foo[0][2],foo[0][3],foo[0][4]);
printf("foo pointers: 0x%x, 0x%x: 0x%x, 0x%x, 0x%x, 0x%x\n", foo[0],
foo[1], &foo[0][0], &foo[0][1], &foo[1][0], &foo[1][1]);
Prints:
sizeof foo(16), bar(8)
foo: 0.0, 0.1, 1.0, 1.1
bar: 0.0, 0.1, 1.0, 1.1
foo pointer: 0.0, 0.1, 1.0, 1.1
foo pointer: 0.0, 0.1, 1.0, 1.1
foo pointers: 0xbffff6d8, 0xbffff6e0: 0xbffff6d8, 0xbffff6dc, 0xbffff6e0,
0xbffff6e4
Confused yet? I am. I always liked libraries/classes that handled this
stuff for me... :-)
b.bum