Dimension of an array when returning from a function

Viewed 87

I can not understand the difference in array size of this example:

#include <stdio.h>

int (*foo(void))[3] {
    static int array[3] = { 1, 2, 3 };
    printf("Dimension inside = %d\n", sizeof(array));
    return array;
}

int main(void) {
    foo();
    printf("Dimension outside = %d\n", sizeof(foo()));
    return 0;
}

In particular the first foo() printa one size (12) while the second call of foo() inside sizeof() give me just 4.

Moreover, what is the purpose the declare that the function return a pointer of an array of 3 int? A thing like int *foo(void) would be the same. Right?

2 Answers

This & returns pointer to array and not to the first int:

return &array;

Same value, different type.

With *foo() foo's return value can be dereferenced and have it's size taken:

sizeof(*foo());

I get size 12 inside and outside, and no warnings.

Whereas foo() and &foo have 8 as size.

*foo() means *(foo()) but the parens can be left away.

Purpose?

To return a pointer to a static array is already questionable - why not declare the array itself outside the function?

Then it depends what you really want. -Wall indicates this basic problem:

warning: returning 'int *' from a function with
         incompatible return type 'int (*)[3]'

--> Foo() is inconsistent in itself.

As a simple int *foo() you can use foo() like a 3-int array:

printf("%d\n", foo()[1] );   // prints "2"

With a second dimension (return &array) it becomes:

printf("%d\n", foo()[0][1] );

The program has undefined behavior for multiple reasons:

  • printf("Dimension inside = %d\n", sizeof(array)); passes a size_t when printf expects an int value for %d: use %zu instead.

  • return array; is a type mismatch: you define the function as returning a pointer to an array of 3 int. Return &array to fix this.

  • printf("Dimension outside = %d\n", sizeof(foo())); has the same conversion problem, and you print the size of a pointer instead of that of the object pointed to which is why you get different sizes. Use this instead:

    printf("Dimension outside = %zu\n", sizeof(*foo()));
    
  • also note that there is no second call to foo(): sizeof(foo()) does not evaluate its argument, it simply evaluates to the size of the return type of foo() at compile time, but does not generate a function call.

  • int *foo(void) would mean something different: it would define foo() as returning a pointer to int, which by the way would be consistent with returning array.

Here is a modified version:

#include <stdio.h>

int (*foo(void))[3] {
    static int array[3] = { 1, 2, 3 };
    printf("Dimension inside = %zu\n", sizeof(array));
    return &array;
}

int main(void) {
    foo();
    printf("Dimension outside = %zu\n", sizeof(*foo()));
    return 0;
}

Output:

Dimension inside = 12
Dimension outside = 12

This explanation aside, it is not idiomatic for a function to return a pointer to an array and many a C programmer will mentally parse the function definition incorrectly and miss the subtlety of this approach.

Related