0

int data[3][5];

is a 3-element array of 5-element arrays.

Why? Intuitively for me if int[3] is a 3-element array and int[3][5] Should be a 5-element array of 3-elements arrays.

xvan
  • 4,554
  • 1
  • 22
  • 37
  • Intuition has no significance here. That is the syntax of the language. You'll just have to get accustomed to it. – machine_1 Jan 29 '20 at 19:08
  • You can always declare a [new type](https://wandbox.org/permlink/1wGceoeBFrwrmYUq), if it's more readable to you. – Bob__ Jan 29 '20 at 19:13
  • 2
    Suppose `data[i][j]` referred to element `i` of the array `j` of the arrays in `data`. Then what would `data[i]` refer to? `data` is an array of arrays, so `data[i]` can only pick arrays out of it, not `int` elements. You would have to have `data[j]` be array `j`, and then inserting `[i]` between the two picks out an element. That is weird—C syntax builds on expressions; to do something to `data[j]`, you apply more operators outside it; you do not insert something into it. – Eric Postpischil Jan 29 '20 at 19:27
  • Another way of looking at it is that, in `data[i][j]`, the compiler would have to figure out what the `data…[j]` is (an array) before it can figure out what the `[i]` does. – Eric Postpischil Jan 29 '20 at 19:28
  • @EricPostpischil, I have no issue with the intuition of the indexing syntax, but with the declaration syntax. EugeneSh. answer tries to link both, guess I'll have to accept that as the reason. – xvan Jan 29 '20 at 19:35
  • 2
    The declaration matches the use. [The declaration gives a picture of use](https://stackoverflow.com/a/59436836/298225); `int data[3][5]` says that, when `data[i][j]` appears in the source code, it is an `int`. Since `data[i][j]` is an `int`, `data[i]` must be an array of `int`, so `data` must be an array of arrays of `int`. – Eric Postpischil Jan 29 '20 at 20:32

3 Answers3

5

The intuition should come from the indexing convention - since it is an array of arrays, first index is selecting the element which is an array, the second index is selecting the element of the selected array. That is:

data[2][4] will select element number 4 of the array number 2 (mind the zero-basing).

Now the definition of such an array seems to be a bit counter-intuitive as you noted, but apparently it is this way just to be consistent with indexing syntax, otherwise it will be much more confusing.

Eugene Sh.
  • 17,802
  • 8
  • 40
  • 61
  • I changed the example to one inside the array shown in the question (`int data[3][5]` does not contain an element indexed `[2][5]` but does contain one indexed `[2][4]`, but I suggest you change the ordinal references as well. While it is tempting to call the element indexed `[0]` the “first” element, it is confusing. One can say “`a[2][4]` selects element number 4 of array number 2.” – Eric Postpischil Jan 29 '20 at 19:24
  • @EricPostpischil Thanks, I imagined your edit is to match the example with the question. Will take your other suggestion as well. – Eugene Sh. Jan 29 '20 at 19:30
1

C doesn't always work in an intuitive way because of things like the spiral rule, though maybe you're mis-applying it here.

As with any language, you need to accept the syntax for what it is, not what you think it is, or you'll constantly be fighting with the language on a semantic level.

Tools like cdecl explain it as:

declare data as array 3 of array 5 of int

tadman
  • 208,517
  • 23
  • 234
  • 262
1

This falls out of C's concept of declarators. The pointer-ness, array-ness, or function-ness of a declaration is specified in the declarator, while the type-ness is specified with a type specifier1:

int *p;              // *p is the declarator
double arr[N][M];    // arr[N][M] is the declarator
char *foo( int x );  // *foo( int x ) is the declarator

This allows you to create arbitrarily complex types in a compact manner:

int *(*foo(void))[M][N];

foo is a function taking no parameters, returning a pointer to an M-element array of N-element arrays of pointer to int.

Thus, the actual type of an object or function is specified through the combination of the type specifier (and any qualifiers) and the declarator.

Unfortunately, "compact" is just another way of saying "eye-stabby". Declarations like that can be hard to read and understand. It does mean that things like multi-dimensional array declarations read kind of "backwards":

  +---------------------------------+
  |                                 |
  v                                 |
type   arr -> array-of -> array-of -+
        ^
        |
    start here

But, if you work it through, it does make sense. Let's start with some arbitrary type T. We declare an array of T as

T arr[N];

Thus, arr is an N-element array of T. Now we replace T with an array type R [M]. This gives us

R arr[N][M];

arr is still an N-element array of something, and that something is R [M], which is why we write arr[N][M] instead of arr[M][N].


  1. And there are also storage-class qualifiers, type qualifiers, etc., but we won't go into those here.

John Bode
  • 119,563
  • 19
  • 122
  • 198