Sayandeep Mitra
Sayandeep Mitra

Reputation: 49

3-d array operations in c

main()
{
int a[2][3][2]={{1,2},{9,8},{3,7}},{{2,2},{1,4},{5,4}};
printf("%d %d %d",a[1]-a[0],a[1][0]-a[0][0],a[1][0][0]-a[0][0][0]);
}

The output given in the book is 3 6 1. I am unsure about the working of 3-d array. Could someone please explain to me the entire process of the above code?

Upvotes: 0

Views: 116

Answers (2)

Jonathan Leffler
Jonathan Leffler

Reputation: 753615

Diagrammatically, the array initialized as:

int a[2][3][2] = { {{1,2},{9,8},{3,7}}, {{2,2},{1,4},{5,4}} };

(note the extra pair of braces that are necessary compared with the code in the question) looks like this in memory:

|                                   a                                   |
|                a[0]               |                a[1]               |
|  a[0][0]  |  a[0][1]  |  a[0][2]  |  a[1][0]  |  a[1][1]  |  a[1][2]  |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|  1  |  2  |  9  |  8  |  3  |  7  |  2  |  2  |  1  |  4  |  5  |  4  |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
^                       ^                       ^                       ^ 
0x1000                  0x1010                  0x1020                  0x1030

The starting address is hypothetical and convenient rather than realistic; I'm assuming sizeof(int) == 4, which is the most common value but not guaranteed by the standard. In the discussion below, address ranges include the start address and exclude the end address.

What this diagram shows is that the 12 numbers are laid out linearly in memory as shown. The entire array, a has a size of 48 bytes, therefore, from address 0x1000 to 0x1030. The sub-array a[0] extends from address 0x1000 to 0x1018; the sub-array a[1] extends from 0x1018 to 0x1030. The sub-array a[0][0] extends from 0x1000 to 0x1008; a[1][0] from 0x1018 to 0x101C; and so on.

Now let's look at the printf() statement:

printf("%d %d %d", a[1]-a[0], a[1][0]-a[0][0], a[1][0][0]-a[0][0][0]);

We can observe (and my compiler did observe, as I expected it to), that the first two values are actually of type ptrdiff_t and therefore the correct format specifier is %td, not %d (though on a 32-bit platform, %d would be OK, and on a 64-bit platform, %ld would be OK, but to be correct on both, you need to use %td). It would also be better if the output ended with a newline.

It is easy to agree that the value of a[1][0][0] is 2, and the value of a[0][0][0] is 1, so the third number printed should be 1, and indeed that is the output.

Working backwards, a[1][0] is an array (of two int elements, so the size is 8 bytes) starting at address 0x1018; similarly, a[0][0] is an array starting at address 0x1000. However, because of the 'decay' of an array, these values are equivalent to int * (so *a[0][0] is equal to a[0[0][0] or the value 1) , so the raw difference in bytes (0x18 = 24) is scaled by the size of the object pointed at (int or 4), yielding the answer 6.

Similarly, a[1] is an array (of type int [3][2]), and so is a[0]. The difference is again 0x18 = 24 bytes, but this time, *a[1] is a pointer to an array of 2 int and is of size 8, therefore, so the answer is 3.

Thus, as expected, the correct output from the program is:

3 6 1

Further, although the addresses would be different, the calculation would be accurate if sizeof(int) == 2 or if sizeof(int) == 8 (or, indeed, any other size, though those are the main plausible candidates on modern general purpose hardware; DSP hardware might have sizeof(char) == sizeof(int) — and therefore sizeof(int) == 1 — and CHAR_BIT == 16 or even, perhaps, CHAR_BIT == 32).

Upvotes: 2

Some programmer dude
Some programmer dude

Reputation: 409166

An array can be of any other type, including other arrays. So what you have is an array of two arrays of three arrays of two integers.

Upvotes: 0

Related Questions