3

what will be the dimension of integer array arr if declared like this :

int arr[][2]={1,2,3};

what is the use of not declaring the highest dimension ?

Gilles 'SO- stop being evil'
  • 104,111
  • 38
  • 209
  • 254
Kroor Singh
  • 255
  • 2
  • 7
  • 1
    Flexibility. The compiler infers the size in that dimension itself, so if you add more elements, you don't have to change the constant in the declaration. (But does this compile?) –  Aug 08 '13 at 19:37

2 Answers2

5

Somewhat to my surprise, your declaration:

int arr[][2]={1,2,3};

appears to be legal. You can legally omit inner braces in initializers. For example, if you wanted to define the bounds of arr explicitly and initialize all its elements, you could write either:

int arr[2][2] = { { 1, 2}, { 3, 4 } };

or, equivalently:

int arr[2][2] = { 1, 2, 3, 4 };

You can also omit trailing elements, and they'll be implicitly set to zero. For a one-dimensional array, this is straightforward; this:

int arr[4] = { 1, 2, 3 };

is equivalent to:

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

And if you omit a dimension, it can be inferred from the initializer:

int arr[] = { 1, 2, 3, 4 }; // 4 elements

Since you're defining arr as an array of 2-element arrays of int, this:

int arr[][2]={1,2,3};

is equivalent to this:

int arr[][2] = { { 1, 2 }, { 3 } };

You have two elements in the initializer (each of which initializes a 2-element array), so that's equivalent to:

int arr[2][2] = { { 1, 2 }, { 3 } };

Finally, you've omitted the last initializer sub-element, so it's implicitly zero:

int arr[2][2] = { { 1, 2 }, { 3, 0 } };

In general, omitting dimensions and trailing initializers is useful because it lets the compiler figure out certain things. If I write:

char message[] = "hello, world";

I don't have to count the characters in the string (and add 1 for the terminating '\0'). Computers are really good at counting things; making a human do that job would be silly.

Similarly, omitting some initializers lets you provide only the information you need. With C99's addition of designated initializers, you can even initialize a specified member of a structure and let the compiler take care of everything else:

struct foo obj = { .something = 42 };

As for flattening initializers by omitting inner curly braces, I personally don't see much use for that except for the special case of using a { 0 } initializer to initialize and entire array or structure to zero. In particular, for multidimensional arrays I find it much clearer to show the entire structure of the array.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • Not true. Last element is junk, according to gcc and g++. – Jiminion Aug 08 '13 at 19:56
  • 1
    @Jim: Do you have a citation for that? The ISO C standard says "all subobjects that are not initialized explicitly shall be initialized implicitly the same as objects that have static storage duration", i.e., to zero. (If there's no initializer at all and the object is defined at block scope, the initial value is garbage.) – Keith Thompson Aug 08 '13 at 20:22
  • Well, I built a routine and tested it. Is that citation enough? – Jiminion Aug 08 '13 at 20:26
  • What does initialized implicitly mean? I thought individual variables (ints, chars, etc.) are initialized, but not so arrays. – Jiminion Aug 08 '13 at 20:28
  • @Jim: If there's no initializer, objects defined at file scope are initialized recursively to zero for each appropriate type; objects at block scope (inside a function) without `static` are uninitialized garbage. If the declaration includes an initializer, any (sub)components not explicitly initialized are set to zero. Can you post your test routine somewhere? – Keith Thompson Aug 08 '13 at 20:33
  • I put it in your answer (hope that's OK). It works ok if the int i,j and next two lines are removed. – Jiminion Aug 08 '13 at 20:38
  • OK, I pasted it in MY answer. – Jiminion Aug 08 '13 at 20:53
  • 1
    @jim: `arr[1][2]` is out of bounds. `arr[1][1]` is `0`. – Keith Thompson Aug 08 '13 at 20:55
1

Per the minimal bracketing rule (6.7.9p20 in C11),

enough initializers from the list are taken to account for the elements or members of the subaggregate or the first member of the contained union; any remaining initializers are left to initialize the next element or member of the aggregate of which the current subaggregate or contained union is a part.

So the following declarations are equivalent:

int arr[][2]={1,2,3};
int arr[][2]={{1,2},{3}};
int arr[2][2]={{1,2},{3}};

As to why this is useful: when initializing a large multi-dimensional array, it may well be obvious to the reader how many items there are per subaggregate; in which case, there is no need to supply the brackets between subaggregates.

ecatmur
  • 152,476
  • 27
  • 293
  • 366