Experiments using sizeof with arrays and pointers Experiments using sizeof with arrays and pointers arrays arrays

Experiments using sizeof with arrays and pointers


Please answer the questions and correct me if any of the observations are wrong.

  1. Is Case 1 output 20 because b was declared as an array of integers ie int[]? The total block in bytes is returned as confirmed by Fact1. Isn't it?

Yes, the result shows the sizeof(int [5]). So from Fact1, the size is 5*4

  1. I guess casting b to int* made the difference here. Here b is considered a pointer. I confirmed this using Fact2. Right or wrong?

Right. But adding more info: sizeof needs only the type of expression and it does not evaluate expression (for value) unless it is VLA type.(From section 6.5.3.4 The sizeof operator of C99 specs)

Because you are applying cast on final result, anything after that does not matter.

  1. &b[0] decays to a pointer b. The output coincides with Fact2 .

No and yes. Type of b[0] is int and thus type of &b[0] is already int *(Recall that [...] binds tighter than &). There is no decaying. And yes the output coincides with Fact2.

  1. I expected 16 here but I got 8 as the output. I concluded that this is because a is afterall a pointer and the output coincides with Fact2 . I got the output similar to Question 2.

a as pointer to array 2 of int. So the printed size is of pointer (to an int array).

int (*a)[2]; declares a as pointer to array 2 of int. So you get the size of pointer to array.

To get the desired result (size of array 2 of pointers to int) use: int *a[2];

int (*a)[2];a           anonymous+----+      +----+----+| a  |----->|int |int |+----+      +----+----+int *b[2];b  +----+----+|int*|int*|+----+----+b[0] b[1]
  1. a[0] is pointer. The output coincides with Fact2
  2. a[2] is pointer. The output coincides with Fact2

As stated earlier, a is a pointer to array 2 of int. So a[index] is an array 2 if int. So, type of a[0] and a[1] are array 2 of int. So the output is 2*4 from Fact 1.
Possibly irrelevant to this answer but a is uninitialized and using it in expression would cause undefined behaviour. Though it is fine to use in sizeof


To understand the output, let's analyse the type of argument of sizeof

printf("sizeof(b) : %zu\n",sizeof(b));             // int [5]printf("sizeof((int*)b) : %zu\n",sizeof((int*)b)); // int *printf("sizeof(&b[0]) : %zu\n",sizeof(&b[0]));     // int *printf("sizeof(a) : %zu\n",sizeof(a));             // int (*) [2]printf("sizeof(a[0]) : %zu\n",sizeof(a[0]));       // int [2]printf("sizeof(a[1]) : %zu\n",sizeof(a[1]));       // int [2]

A portable program (not foolproof) to confirm the types looks like:

assert(sizeof(b) == sizeof(int [5]));assert(sizeof((int*)b) == sizeof(int *));assert(sizeof(&b[0]) == sizeof(int *));assert(sizeof(a) == sizeof(int(*)[2]));assert(sizeof(a[0]) == sizeof(int[2]));assert(sizeof(a[1]) == sizeof(int[2]));


The sizeof operator is one of the few things that can distinguish between an array (assuming it's not a function parameter) and a pointer.

  1. b is recognized as an array of 5 elements where each is 4 bytes, so sizeof(b) evaluates to 20.
  2. The cast converts the array to a pointer in a similar way as passing it to a function would. So the size is 8.
  3. This is not actually decaying to a pointer. It is a pointer. You're taking the address of an int, so of course the type is int *. Addressing one of your comments, it is still not accurate to say the expression &b[0] decays to a pointer if you pass it to a function, because it is in fact a pointer, not an array.
  4. Since a is a pointer to an array, the size is the size of a pointer, i.e. 8. This is different from int *c[2], which is an array of pointers and would have size 16.
  5. a[0] is not a pointer but an array of size 2. The syntax a[0] is equivalent to *(a + 0). So since a is a pointer to an array, dereferencing a gives us an array. Since each element is 4 bytes the size is 8. If a was defined as int (*a)[3] then sizeof(a[0]) evaluates to 12.
  6. Similar to number 5, a[1] is an array of size 2. So sizeof(a[1]) evaluates to 8 because it is an array of 2 elements of size 4.

An example of how to use a is as follows:

int (*a)[2];int d[3][2];a=d;d[0][0]=1;d[0][1]=2;d[1][0]=3;d[1][1]=4;d[2][0]=5;d[3][1]=6;printf("a00=%d\n",a[0][0]);printf("a01=%d\n",a[0][1]);printf("a10=%d\n",a[1][0]);printf("a11=%d\n",a[1][1]);printf("a20=%d\n",a[2][0]);printf("a21=%d\n",a[3][1]);

Output:

a00=1a01=2a10=3a11=4a20=5a21=6

You also use this when passing a 2D array to a function:

void f(int (*a)[2]) {    ...}int main(){    int x[3][2];    f(x);}


Here is a bit of individual research on the subject.I've run your test code in four different environments, two 64bit and two 32bit.
I used three different compilers: llvm, gcc and mipsPro cc.
Here is the commented comparison of the results:

// 64-bit environment - all compilerssizeof(int) :     4 -> Fact 1       -32 bit int -> 4 bytes   sizeof(int*) :    8 -> Fact 2       -this and other pointers in a 64-bit system are 8-bytes longsizeof(b) :      20 -> Case 1       -array of 5 32 bit ints -> 20 bytessizeof((int*)b) : 8 -> Case 2sizeof(&b[0]) :   8 -> Case 3sizeof(a) :       8 -> Case 4sizeof(a[0]) :    8 -> Case 5       -array of two 4 byte intssizeof(a[1]) :    8 -> Case 6       -array of two 4 byte ints// 32-bit environments - all compilerssizeof(int) :     4 -> Fact 1       -32 bit int -> 4 bytes sizeof(int*) :    4 -> Fact 2       -this and other pointers in a 32-bit system are 4-bytes longsizeof(b) :      20 -> Case 1       -array of 5 32 bit ints -> 20 bytessizeof((int*)b) : 4 -> Case 2sizeof(&b[0]) :   4 -> Case 3sizeof(a) :       4- > Case 4sizeof(a[0]) :    8 -> Case 5       -array of two 4 byte intssizeof(a[1]) :    8 -> Case 6       -array of two 4 byte ints

Interpretation - all results consistently match the following pattern:

  • Size of int used to depend on the compiler, and perhaps still does, AFAIK. It is in all tested environments and compilers 4-byte (Fact 1).
  • Size of all pointers defaults to the environment, either 64bit or 32bit (Fact 2, Case 2, 3, 4).
  • Size of an array of two four-byte ints equals 2*sizeof(int) (Case 5, 6).
  • a[0] can be rewritten as *a; a[1] can also be written as *(a + 1). The following SO post elaborates it in detail.

    Hope this can contribute to your topic.