Sizeof confusion

I am a little confused concerning the usage of sizeof with arrays. On page 65 of the lecture notes it says:
Bildschirmfoto 2022-05-16 um 15.01.40

However three lines later there is this note which seems to contradict the first statement:
Bildschirmfoto 2022-05-16 um 15.02.51

Can someone clarify this for me? Is sizeof(numbers) 400000 because we get the size of 100000 pointers and because we know that when sizeof(int)=4, sizeof(*int)=4?

1 Like

There is an important difference between an array which is statically declared with type int[], and a pointer to the first element of an array. First of all, the type int[] is really the type int[N] in disguise in the example below (actually not in all contexts…), where N is the length of the array. The length is therefore part of the type itself.

int x[] = { 2, 3 };

Here x is declared with type int[2] by syntactic sugar. So what is the type of x? Now, C is a complicated language, the type of an expression also depends on the context it is evaluated in, so the type of x may be different from the type of its declaration. In evaluated context, the type of x will be int * instead of int[2]. This is so-called array-to-pointer conversion, which happens for example when you pass x to a function expecting a int* or when performing pointer arithmetic with x.

sizeof however does not evaluate its operand, here the type of x will be the type it was declared with, so int[2]. The beginner’s mistake the script refers to is not to use sizeof on a variable declared with array type, but to use it on a pointer value which merely points to an array. Consider the following situation:

int x[] = { 2, 3 };
int* y = x; 
// int z[] = x; Not even allowed

What is sizeof(y)? Although y points to an array, the type y was declared with is int*, so sizeof(y) = sizeof(int*). sizeof cannot retreive the length of the array that we point to, since it only gives the size of a type, and the length of the arraywe point to is not part of the declared type of y at all. On the contrary, we have sizeof(x) = sizeof(int[2]) = 2 * sizeof(int).

Note also that there is no rule that states sizeof(int) = sizeof(int*), these sizes can actually be different.

4 Likes

You might wonder: When does this happen? The answer is: almost always. There are only four cases where it does not happen, namely

when it [the array] is the operand of the sizeof operator, the _Alignof operator, or the
unary & operator, or is a string literal used to initialize an array

Let’s look at these:

  • sizeof: Thorsten has already explained this in the post above
  • _Alignof: _Alignof works a bit like sizeof. Where sizeof gives you the size of an object (i.e. an array), _Alignof gives you the alignment. For example, ints typically have an alignment of 4. Arrays usually inherit their alignment from their elements, so an array of int would also have an alignment of 4. Apart from this, these operators are evaluated to numbers at compile-time and behave pretty similar (except that they yield different numbers)
  • &: When you write &numbers in the above example, you get a value of type "pointer to array of int". Such an object is pretty weird, and there is really not much you can do with it, except use * to dereference it and get the pointer back. Since * and & cancel, this feature is mostly useless.
  • Initializing an array: This refers to declarations like char c[] = "Hello". This is just syntactic sugar for char c[] = {'H', 'a', 'l', 'l', 'o', '\0'}. But, since "Hello" is a string literal, and thus has type char[], this needs to be explicitly said because this is the C standard, which tries to make everything explicit.

So, these are the four exceptions. Everywhere else you encounter something of type "array of t", this just automatically becomes a "pointer to t". Note that these exceptions are all syntactic. So you can always tell whether your array is converted by looking at the context the array is used in.

5 Likes