0

I have a function which returns a 3-d array of integers as a pointer to the 0th 1-D array of the 0th 2-D array in it. It is of dimensions 2*3*4. Here is my function:

    int (*ultimate())[4] {
        int a[2][3][4] = {
                {
                        {1,2,3,4},
                        {5,6,7,8},
                        {9,10,11,12}
                },
                {
                        {13,14,15,16},
                        {17,18,19,20},
                        {21,22,23,24}
                }
        };
        return (int (*)[4]) a;
    }

I am using this function in two different ways:

In the first method, I am taking the pointer to the 1-D array, and seeing that there are 6 such arrays, print out each one by one:

int (*q)[4];
q = ultimate();
for (int i = 0; i < 2*3; i++) {
    printf("\n");
    for (int k = 0; k < 4; k++) {
        printf("%d ",*(*(q+i)+k));
    }
}

In the next method, I am simply using the return value to get the address of the first element in the 3-D array, and then printing all:

int *p;
    for (int i = 0; i < 2; i++) {
        p = (int *) (q+i*3);
        pnl();
        for (int j = 0; j < 3; j++) {
            for (int k = 0; k < 4; k++) {
                printf("%d",*p);
                p++;
            }
        }
    }

However, in both cases, I am getting junk values. In the first method, I am getting some rows of the array while the other values are junk, while in the second method all values are junk. Any idea where I am being wrong?

SexyBeast
  • 7,913
  • 28
  • 108
  • 196
  • Instead of `*(*(q+i)+k))` you can write `q[i][k]`. (IDK how anyone finds your version more readable) – M.M Jul 06 '14 at 21:25

2 Answers2

2

You are creating the array inside the function on the stack. When the function exits, that memory is reclaimed. So there is no guarantee that you will be able to access those values.

The reason you are getting randomly correct values is that just by chance, that area of memory has not been overwritten yet. To avoid this, either declare the array on the heap using malloc or create a static constant, etc.


EDIT: By static constant I meant a global one outside the function. Technically the lifetime of a static variable inside a function is equal to the lifetime of the program. But because the C spec does not guarantee thread-safety, there may be potential errors while the program is being shut down.

EDIT 2: I managed to find an SO question which describes this problem: What is the lifetime of a static variable in a C++ function?

Community
  • 1
  • 1
metacubed
  • 7,031
  • 6
  • 36
  • 65
  • Thanks! I should have declared the array as static! Now it works fine for both, as expected. – SexyBeast Jul 06 '14 at 20:21
  • And I am not returning an array type, right? I am returning a pointer, which has been cast appropriately. Why is that wrong? – SexyBeast Jul 06 '14 at 20:21
  • Where did you declare it static? Don't do it inside the function - that can still fail. – metacubed Jul 06 '14 at 20:21
  • Declaring static inside may fail? How come? – SexyBeast Jul 06 '14 at 20:22
  • @metacubed returning an `int***` is impossible here. There are no pointers being pointed at. His code returns a pointer to `int[4]`, which is correct (although poor style IMO) – M.M Jul 06 '14 at 21:23
  • @MattMcNabb yes I should have said `int**` which is nearer to the "pointer to `int[4]`" he is returning. And also, even though I don't like returning a pointer to `int[4]` myself, it seems to be valid C. Scoping was the actual issue in this case. – metacubed Jul 06 '14 at 21:32
  • @metacubed `int **` does not work either. I recommend just deleting your third para; it's wrong on both counts and as you say, it is nothing to do with the actual issue – M.M Jul 06 '14 at 21:47
  • @MattMcNabb I will delete the third para. Though int** should work. Should we start up a chat rather than spamming the comments? – metacubed Jul 06 '14 at 21:49
  • Try to write a program where `int **` works and you will discover the problem. It sounds like you're mentally equating arrays with pointers. However they are different. An `int **` **must** point to an `int *` , however in `int a[2][3][4]` there are no `int *`'s to point at. There are only arrays. – M.M Jul 06 '14 at 21:53
1

In C/C++ Functions may not declare an array as a return type.

For example in the C Standard there is written

6.7.6.3 Function declarators (including prototypes) Constraints 1 A function declarator shall not specify a return type that is a function type or an array type.

As for your code then it has undefined behaviour because the function returns pointer to a local object that has type of an array. After exiting the function the array will be destroyed.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335