getynge
getynge

Reputation: 135

Why does sizeof(argv)/sizeof(argv[0]) give me the size of an array in C++?

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

Answers (1)

Keith Thompson
Keith Thompson

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 cv char*.

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

Related Questions