Gabriel Saul
Gabriel Saul

Reputation: 65

Returning a pointer to an array of structs

Let's say I have to create an array of structs that is allocated on the heap and return a pointer that points to this array of structs.

typedef struct Pair {
    int x;
    int y;
} Pair;

Pair** foo(int n, int m, int length)
{
    Pair* arr = malloc(sizeof(*arr) * length);

    for (int i = 0; i < length; ++i) {
        arr[i].x = n++;
        arr[i].y = m++;
    }

    return &arr;
}

When I compile a program containing this function, it warns me that I am returning the address of a local variable. I assume this is because the pointer is initialised within the function (i.e. on the stack), therefore it counts as a local variable.

When I compile it, ignoring this warning, and run it anyway, the program crashes when the returned pointer is accessed.

I have tried allocating the pointer dynamically:

Pair** ptr = malloc(sizeof(**ptr));
ptr = &arr;
...
return ptr;

but the program still crashes when this pointer is accessed. How can I create this array within a function and return a pointer to this array so that it can be safely accessed?

Upvotes: 1

Views: 153

Answers (4)

Linh Nguyen
Linh Nguyen

Reputation: 51

Because arr is a local variable, it will be free when foo end. So you don't have access for arr after. To solve this you should declare array pointer in heap:

     Pair** foo(int n, int m, int length)
     {
           Pair ** arr = (Pair**)malloc(sizeof(Pair*));
           *arr = malloc(sizeof(Pair) * length);

           for (int i = 0; i < length; ++i) {
               (*arr)[i].x = n++;
               (*arr)[i].y = m++;
           }

            return arr;
       }

Upvotes: -1

Joseph Quinsey
Joseph Quinsey

Reputation: 9962

If you want an array of structs, the code:

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int x;
    int y;
} Pair;

static Pair* foo(int n, int m, int length)   {
    Pair* arr = malloc(sizeof(*arr) * length);
    for (int i = 0; i < length; ++i) {
        arr[i].x = n++;
        arr[i].y = m++;
    }
    return arr;
}

int main(void) {
    Pair *z = foo(111, 222, 3);
    for (int i = 0; i < 3; ++i) 
        printf("z[%d]= { %d, %d }\n", i, z[i].x, z[i].y);
    free(z);
    return 0;
}

gives the output:

z[0]= { 111, 222 }
z[1]= { 112, 223 }
z[2]= { 113, 224 }

Upvotes: 1

Miket25
Miket25

Reputation: 1903

If you want an pointer to an array of structs, you can change your function signature from Pair** to be Pair*.


If you still want an pointer to an array of pointers, then allocate memory for a Pair struct for each index of arr.

for(int i = 0; i < length; ++i){
    arr[i] = malloc(sizeof(Pair));
    ...
}

Instead of returning &arr, you can declare arr as

Pair** arr = malloc(sizeof(Pair*) * length);

Upvotes: -1

Programmer dude
Programmer dude

Reputation: 167

This array is initialized on the stack but the pointer (arr) is a local variable, so the caller, main, cannot access it. You do not need to use the address of the pointer. You can access the array with the pointer itself.

Pair* foo(int n, int m, int length)
{
    Pair* arr = malloc(sizeof(*arr) * length);

    for (int i = 0; i < length; ++i) {
        arr[i].x = n++;
        arr[i].y = m++;
    }

    return arr;
}

Upvotes: 4

Related Questions