4

I know I can explicitly initialize a 1-d array as follows:

int a1d[] = {0, 1, 2, 3, 4, 5};

This array will have exactly 6 elements - sizeof(a1d) / sizeof(a1d[0]) tells me so.

I'm trying to do this with a 2- (or more) dimensional array:

int a2d[][] = {{0, 1, 2}, {3, 4, 5}};

But gcc errors with error: array type has incomplete element type. It would seem that it is explicit from the initialization that this is a 2x3 array, but it would seem this isn't allowed - why is this?

Instead I have to specify all but one dimensions:

int a2d[][3] = {{0, 1, 2}, {3, 4, 5}};

I understand that if I am going to pass an n-dimensional array to a function, then it is absolutely necessary for n-1 dimensions to be specified in the function, as explained by this question Why do we need to specify the column size when passing a 2D array as a parameter?, but it is less obvious to me for the explicitly-initialized case. Is this just a limitation of the standard, or is there a compelling technical reason for this I am missing?

Community
  • 1
  • 1
Digital Trauma
  • 15,475
  • 3
  • 51
  • 83
  • so that the compiler can determine how to layout the (non-jagged) array in memory. – Mitch Wheat Oct 10 '13 at 00:26
  • @MitchWheat - but isn't that obvious from the initialization? Or are compilers just not smart enough to figure that out? – Digital Trauma Oct 10 '13 at 00:28
  • @MitchWheat - can you expand on exactly what you mean by "jagged" here? – Digital Trauma Oct 10 '13 at 00:30
  • 1
    Memory is 1D, therefore a 2D array must be squished into 1D before it can be stored in memory. Your array would be stored in memory sequentially with the first row followed by the second row: {0,1,2,3,4,5} so the compiler must know how "wide" a row is so it can index your array properly. Say you wanted element [x][y], the compiler would translate that into index x+RowLength*y in the 1D version of your array. – George Mitchell Oct 10 '13 at 00:38

1 Answers1

3

One reason is that it is permissible to initialize an array with an initializer like this:

= { { 1 }, { 2, 3 }, { 4, 5, 6 } };

It is not obligatory to provide every initializer. Indeed, with designated initializers, that could become:

= { [23] = { 1 }, [9] = { 2, 3 }, [3] = { [13] = 4, [99] = 5, [0] = 6 } };

So the array that that is an initializer for must be at least:

int a[24][100];

Partly, it dates back to the ancient history of C when the compiler had to fit into 64 KiB memory, etc. The extra work needed to deduce the size of the array by the compiler was probably too great for the capacity of the machines (especially compared with the cost of having the user specify explicitly how big an array they wanted — the saved typing is minimal).

NB: 'permissible' does not mean 'recommended'.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Furthermore, processing the initializers while the dimensions are not fully known requires either a complicated data structure to remember them or, when one of the lists is found to contain more elements than previous used for that dimension, rearranging the previously processed elements in the compiler’s memory to suit the new dimensions. In contrast, when only the outermost dimension is undetermined, the most that is needed is a `realloc` of more memory. – Eric Postpischil Oct 10 '13 at 00:43