views:

337

answers:

3

All,

This has been bugging me for a while now. In C\C++( i guess java and .NET as well) we do not have to specify the row index in a multi-dimensional array. So, for example i can declare an array of ints as such:

int Array[][100];

I think static arrays in general are represented as contiguous memory on the stack. So, taking a column-major representation, how does the compiler know how much memory to allocate in the above case as it's missing one of the dimensions?

+1  A: 

In java and .NET, don't think about "the stack" -- objects live on the heap. And in C, that's just a declaration -- only a definition actually reserves memory! So that would NOT be an acceptable definition -- if you put it as the only line in file a.c:

$ gcc -c a.c
a.c:1: warning: array ‘Array’ assumed to have one element

so gcc is just treating it as if it were int Array[1][100];, as it warns you it's doing.

Alex Martelli
@Alex But Visual Studio allows one to declare the I way I mentioned though
vj01
Declare it: yes. Use it: no. You'll get a LNK2001 error since there's no definition.
Hans Passant
Well, in C, just like in C++ `int Array[][100]` is a *definition*. The only reason it silips through in C is becuse of the C-specific rules for *tentative definitions*.
AndreyT
+1  A: 

It does not know how much memory to allocate, what he knows with array[] is that array is a pointer (like int *array). array[][100] ( someone please correct me if i am wrong ) is the same as array[100].

empc
@empc I think that's not true for statically declared arrays though. For statically declared arrays memory should be allocated at compile time on the stack
vj01
@vj, nope, not necessarily on the stack -- static data are fully allowed to live on other segments. @empc, `int array[100];` is just 400 bytes (in a 32-bit build), `int array[][100]` is a completely different beast -- closer to `int bah[];` (a declaration, **not** a definition!).
Alex Martelli
every day, is a learn day @Alex ;)
empc
+1  A: 

In C++ language you can't just do

int Array[][100]; /* ERROR: incomplete type */

because that would be a definition of an object of incomplete type, which is explicitly illegal in C++. You can use that in a non-defining declaration

extern int Array[][100];

(or as a static member of a class), but when it will come to the actual definition of the same array object both sizes will have to be specified explicitly (or derived from an explicit initializer).

In C the situation is not much different, except that in C there are such things as tentative definitions which let you write

int Array[][100];

However, a tentative definition in this regard is pretty similar to a non-defining declaration, which is why it is allowed. Eventually you will have to define the same object with explicitly specified size in the same translation unit (some compilers don't require that as an non-stanard extension). If you try something like that in a non-tentative definition, you'll get an error

static int Array[][100]; /* ERROR: incomplete type */

So, if you think of it, aside from tentative definitions, the situation in C and C++ is not much different: it is illegal to define objects of incomplete type in these languages and an array of unspecified size is an incomplete type.

AndreyT
Tho you don't need to put an explicit definition of it completing the type, because if no explicit external definition is provided (and all definitions are tentative), the object is implicitly initialized at the end of the TU with an initializer equal to `0`: This will make both the type of the array complete, giving it size of 1, and provide the external definition that's needed. See 6.9.2, and its "Example 2" in paragraph 5 of n1256. The nonstandard extension is that you can provide another definition in another TU (thus having multiple external definitions of the same object, causing UB).
Johannes Schaub - litb
I thought about it (didn't notice the example though), but I found the the wording in 6.9.2 inconclusive. It says that if there's no explicit non-tentative definition, the compiler-provided one will be equivalent to one with "with an initializerequal to 0". It is not clear what exactly it is supposed to mean. Apparently, the intent was that the implied initializer should look as `... = { 0 }` (as opposed to `... = 0`), but for some reason they don't spell it out.
AndreyT
As for the non-standard extension, as far as I know, the "extended" compilers simply treat the tentative definition as non-defining declarations, i.e. a non-tentative definintion in another translation unit *with more than one array element* will be used for all translation inits (if available).
AndreyT
Agreed about the strangeness of "with an initializer equal to 0" :)
Johannes Schaub - litb
I was thinking of J.5.11 describing that "common extension". I think GCC puts such definitions without initializers in a COMMON section (can be disabled by `-fno-common`), where at link-time they are merged together, with the object having the largest size being emitted. Not sure tho about these details :)
Johannes Schaub - litb