Reputation: 135
If I have an array as an argument in main
int main(int argc, char* argv[])
why will
sizeof(argv)/sizeof(argv[0])
always reliably give me the length of the array?
Upvotes: 3
Views: 4881
Reputation: 263357
It doesn't.
I probably got a bit carried away when writing this answer; it's too much of a language-lawyer approach to a fairly simple question. I'll add this quick summary which should be enough to answer the question. The pedantic and overly verbose version of the answer is below the horizontal line.
Given:
int main(int argc, char* argv[])
argv
isn't an array at all; it's a pointer. (C and C++ don't permit parameters of array type; something that looks like an array parameter is really a pointer parameter.) argv
does point (at run time) to the first element of an array, but there's no information in the declaration about how big that array is. That's why we need the argc
parameter to provide that information.
So sizeof(argv)/sizeof(argv[0])
doesn't give you the number of elements in an array; it just divides the size of a pointer by the size of a pointer, which probably gives you 1
. (Why only "probably"? That's part of the overly pedantic answer below.)
Now if you define something explicitly as an array object:
int an_array[42];
you can use that idiom to compute the number of elements in the array:
sizeof an_array / sizeof an_array[0]
This yields 42
, the number of elements in the array. The way it works is (I think) fairly straightforward: it's the size in bytes of the whole array divided by the size in bytes of one of its elements.
But it works only for an actual array, not for something like argv
that looks like an array but is really a pointer.
The relationship between arrays and pointers can be confusing. Section 6 of the comp.lang.c FAQ explains it very well, and most or all of it applies to both C and C++.
Now the long-winded pedantic explanation with too many digressions:
argv
is a pointer, specifically a pointer to pointer to char
. As a parameter declaration (and only in that context), char *argv[]
is equivalent to char **argv
.
sizeof (argv)
is the number of bytes in a char**
pointer.
sizeof (argv[0])
is the number of bytes in a char*
pointer.
sizeof (argv) / sizeof (argv[0])
is very likely to be 1 (assuming that char*
and char**
have the same size, which they do in most implementations).
Now for something that's been defined as an array object:
some_type an_array[COUNT];
that expression does work; this:
sizeof an_array / sizeof an_array[0]
does give you the number of elements in an_array
, namely COUNT
. The reason for that should, I think, be fairly obvious. The number of bytes in an array is the number of bytes in one element of the array multiplied by the number of elements. So:
sizeof an_array == sizeof an_array[0] * COUNT
and, rearranging the terms:
sizeof an_array / sizeof an_array[0] == COUNT
Incidentally, sizeof an_array[0]
can also be written as sizeof *an_array
, due to the way the indexing operator is defined in C.
(Note that the sizeof
operator doesn't require parentheses around its argument, if that argument is an expression such as an object name. The operand to sizeof
is either an expression or a parenthesized type name. But if you prefer to always use parentheses with sizeof
, you can do that.)
This is a common idiom for computing the number of elements in an array -- but it works only if you have the name of the array itself, not a pointer to its first element.
[The following applies to C. I believe it also applies to C++ (I initially didn't notice that the question is tagged C++, not C).]
In answer to a question raised in comments, no, char*
and char**
are not required to have the same size. The C standard's requirements on pointer representation are:
A pointer to void shall have the same representation and alignment requirements as a pointer to a character type. Similarly, pointers to qualified or unqualified versions of compatible types shall have the same representation and alignment requirements. All pointers to structure types shall have the same representation and alignment requirements as each other. All pointers to union types shall have the same representation and alignment requirements as each other. Pointers to other types need not have the same representation or alignment requirements.
Reference: N1570, 6.2.5p28.
The C++ standard has at least some some of this; section 3.9.2 [basic.compound] of the N3485 draft says:
An object of type cv
void*
shall have the same representation and alignment requirements as cvchar*
.
I haven't found the corresponding text for the rest of what I quoted from the C standard.
On a word-addressed machine, a char*
pointer could plausibly require more information to specify both a word and a byte within that word than is needed for a char**
pointer, which only needs to specify an aligned word.
Upvotes: 23