2

Given a quiz question "What's the value returned by the following function:".

size_t f(int *a[2][3][4]) {
  return sizeof(*a);
}

Is the answer sizeof(int *) * 3 * 4 correct? By which I mean: Is the following equality guaranteed by the ISO C standard?

sizeof(int *) * 3 * 4 == sizeof(int*[3][4])

I've searched the standard far and wide and came to the same conclusion as the askee of this question. Except their examples and accepted answer talk about an array of arrays. But there cannot be padding between elements of arrays to begin with.

My question is, no matter why. Could an array have trailing bytes that would disrupt the above mentioned equality?

Update: It was asked where did the [2] go. Since a is an argument of a function, its type is actually int *(*)[3][4]. See 6.7.6.3p7

  • 2
    What happened to the `[2]` though? It's in the original code, then disappears in the analysis. – pmacfarlane Dec 31 '22 at 00:32
  • @pmacfarlane please see my update explaining the missing [2]. – Damian Rhodes Dec 31 '22 at 01:11
  • Yes, that's a good update and explains it. – pmacfarlane Dec 31 '22 at 01:19
  • @cafce25 In the argument `a` is declared as a `array 2 of array 3 of array 4 of pointer to int` see [here](https://cdecl.org/?q=int+*a%5B2%5D%5B3%5D%5B4%5D) Since its an argument of a function, `a` is `pointer to array 3 of array 4 of pointer to int` see [here](https://cdecl.org/?q=int+*%28*a%29%5B3%5D%5B4%5D) But I don't believe this is relevant to the asked question so I wont edit it further. – Damian Rhodes Dec 31 '22 at 01:56
  • You're right, C types are hard... – cafce25 Dec 31 '22 at 01:57

1 Answers1

3

According to the C standard, the size of an array is equal to the number of elements in the array multiplied by the size of each element.

In the case of the f() function, the size of *a is equal to sizeof(int*) * 3 * 4, as the type of *a is int*[3][4], which is an array of 3 arrays of 4 int* elements.

The standard does not specify any padding between elements of an array, so the equality sizeof(int *) * 3 * 4 == sizeof(int*[3][4]) is guaranteed to hold.

It is worth noting that the standard does allow for padding between structure members and at the end of a structure, and it is possible for the size of a structure to be larger than the sum of the sizes of its members due to padding. However, this does not apply to arrays.

Update: it was pointed out that the [2] disappeared from OPs questions.

The size of an array is determined by the number of elements in the array and the size of each element. In the case of int*[2][3][4], the size of the array is equal to 2 * 3 * 4 * sizeof(int*), as there are 2 arrays of 3 arrays of 4 int* elements.

When you use the sizeof operator on a type such as int*[3][4], it returns the size of that type, which is equal to 3 * 4 * sizeof(int*). The size of the outer array (int*[2][3][4]) is not included in this calculation, as *a has type int*[3][4], not int*[2][3][4].

In other words, sizeof(*a) is equivalent to sizeof(int*[3][4]), not sizeof(int*[2][3][4]).

The behavior of the sizeof operator and the way in which the size of an array is determined are specified in section 6.5.3.4 of the ISO C standard.

Here is the relevant text from the standard:

The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant.

The size of a struct or union is the sum of the sizes of its members, > including any padding.

This means that the size of an array is equal to the number of elements in the array multiplied by the size of each element, and the sizeof operator returns the size of the type it is applied to.

Some more information can be found here, too: https://en.cppreference.com/w/cpp/language/sizeof

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Max
  • 226
  • 3
  • 9