Arrays as function parameters and sizeof()

A

Andreas Eibach

Hi,

when I had in mind to turn this code (which worked fine in main()) to a
separate function, I stumbled upon this...(of course, it's way bigger than
that, but I hope this short snippet can demonstrate the issue anyway)

-begin code (Ì) -
int main(void)
{
unsigned char rawdata[96] =
{0x32, 0xA7, 0x53, 0x00, 0xE0, 0x20, 0x0F, 0x19,
0x00, 0x00, 0x03, 0x70, 0x43, 0xFA, 0x00, 0x18,
0x4E, 0xAE, 0xFF, 0xA0, 0x4A, 0x80, 0x67, 0x0A
}; /* note, rest is _intended_ to be zeroes */

unsigned long x = 0;
int i;

for(i=0; i < sizeof(rawdata)/(sizeof(unsigned long)); i++)
{
...
x = ((rawdata[i*4+0] << 8) | .....;
/* ... */
}
return 0;
}
-end code (I)-

The for() line contains an i < sizeof(rawdata). In main(), this causes no
problems, however, if we (commonly) assume that the function-internal
variables are completely different, we *may* run into trouble...


-begin code (II)-
unsigned long doMagic (unsigned char[]);

int main(void)
{
unsigned char rawdata[64] = {
0x32, 0xA7, 0x53, 0x00, 0xE0, 0x20, 0x0F, 0x19,
0x00, 0x00, 0x03, 0x70, 0x43, 0xFA, 0x00, 0x18,
0x4E, 0xAE, 0xFF, 0xA0, 0x4A, 0x80, 0x67, 0x0A
}; /* note, rest is _intended_ to be zeroes */

unsigned long x = doMagic(rawdata);
... /* e. g. printf output */
return 0;
}

unsigned long doMagic (unsigned char arr[])
{
int i;
for(i=0; i < sizeof(arr)/(sizeof(unsigned long)); i++)
{
...
x = ((arr[i*4+0] << 8) | ....... ;
}
}
-end code (II)


For an absolute beginner, this looks "working fine", but it does not. :)
sizeof(arr) is *NOT* the size of the array (just as I too thought before),
but merely the size of the small pointer (here it was 4). This caused the
for loop to get exited prematurely.

The only way out with the portable solution was to write a different
doMagic():

unsigned long doMagic (unsigned char arr[], unsigned int len);

and then *externally* enter the function using sizeof(rawdata) as length
"info".
This worked fine.

But ... is there no other way to *compute* the actual size of the array
(here 96) *inside* the function without expecting to have it "pre-chewed" by
the calling routine?

-Andreas
 
A

Andreas Eibach

Eric Sosman said:
Andreas said:
[... sizeof function parameter declared as array ...]
But ... is there no other way to *compute* the actual size of the array
(here 96) *inside* the function without expecting to have it "pre-chewed" by
the calling routine?

No. Although you can write the parameter as if it were an
array, in truth it is a pointer to an element of the array. So
sizeof produces the size of a pointer, not the size of the thing
pointed to nor the size of the whole array of things.

See Question 6.21 -- in fact, most of Section 6 -- in the
comp.lang.c Frequently Asked Questions (FAQ) list

Well I'll be DAMNED.
A zillion FAQs in the net with having most stuff in main() and using a hell
of global variables, but only this one covers *that* very problem.
I stand corrected. Yes that would've been the answer I'd needed. Thanks.
Bookmarked.

-Andreas
 
V

vippstar

For an absolute beginner, this looks "working fine", but it does not. :)
sizeof(arr) is *NOT* the size of the array (just as I too thought before),
but merely the size of the small pointer (here it was 4). This caused the
for loop to get exited prematurely.

The only way out with the portable solution was to write a different
doMagic():

unsigned long doMagic (unsigned char arr[], unsigned int len);

and then *externally* enter the function using sizeof(rawdata) as length
"info".
This worked fine.

But ... is there no other way to *compute* the actual size of the array
(here 96) *inside* the function without expecting to have it "pre-chewed" by
the calling routine?

There's some ways.
You said the rest is intented to be 0:
int main(void)
{
unsigned char rawdata[96] =
{0x32, 0xA7, 0x53, 0x00, 0xE0, 0x20, 0x0F, 0x19,
0x00, 0x00, 0x03, 0x70, 0x43, 0xFA, 0x00, 0x18,
0x4E, 0xAE, 0xFF, 0xA0, 0x4A, 0x80, 0x67, 0x0A
}; /* note, rest is _intended_ to be zeroes */
unsigned long doMagic (unsigned char arr[])
{
int i;
for(i=0; i < sizeof(arr)/(sizeof(unsigned long)); i++)

So you can have an end marker there.
Ie

unsigned char rawdata[N + 4] = { /* ... */ [N] = 1, [N + 1] = 1, [N +
2] = 1, [N + 3] = 1 }; /* [N] = is C99 only */

Then you can break the loop when you encounter those intentional
zeroes, and then you read something that is not zero.
Note your code makes assumptions about the size of unsigned long and
the representation of it. (notice the end marker example code I gave
suffers from the same issues)
*(unsigned long *)rawdata may be a trap representation for example
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,046
Latest member
Gavizuho

Latest Threads

Top