Jay Wong Jay Wong - 2 months ago 11
C Question

Segmentation fault when accessing a 2D array in a structure whose pointer is returned from a function

I made a structure who has two members (

int
and
int**
), and I return the pointer to this structure from one function to
main()
. It is fine to access the
int
value in the structure. However, in
main()
I got Segmentation fault : 11 when I tried to access the element of the 2D array.

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

typedef struct Square {
int value;
int **array;
} Square;

Square * generate();

int main(int argc, char *argv[]){
Square *sqrptr = generate();

printf("%d\n", sqrptr -> value);
/* It prints 1 */

/* Print out the 2D array */
for (int i = 0; i < 3; i++){
for (int j = 0; j < 3 ; j++){
printf("%d ", *(*((sqrptr -> array) + i) + j));
}
printf("\n");
}
/* It gives segmentation fault */

return 0;
}

Square * generate(){
Square mySquare;
mySquare.value = 1;
mySquare.array = malloc(sizeof(int*) * 3);

/* Initialize the 2D array */
for (int i = 0; i < 3; i++){
*(mySquare.array + i) = malloc(sizeof(int) * 3);
for (int j = 0; j < 3; j++){
*(*(mySquare.array + i) + j) = 0;
}
}

/* Print out the 2D array */
for (int i = 0; i < 3; i++){
for (int j = 0; j < 3l ; j++){
printf("%d ", *(*(mySquare.array + i) + j));
}
printf("\n");
}
/* I can see the complete 2D array here */

Square *sqrptr = &mySquare;

return sqrptr;
}


I have tried to generate the
Square
in
main()
, and use one pointer of the structure to access my 2D array. It works fine, so I guess I have missed something when I use a pointer returned from other functions. On the other hand, I can access the
int value
successfully, so I have no clues now.

Could someone please explain the underlying reason for this segmentation fault? Thanks!

Answer

You're returning a pointer to a local variable (&mySquare). Stack memory (where local variables reside) is when the function returns, so the resulting pointer is pointing to invalid memory. Allocate the struct, and return the pointer to heap memory:

Square *my_square = malloc(sizeof *my_square);
//do stuff
return my_square;

Or pass a pointer to a stack variable as argument:

Square * generate(Square *my_square)
{
    //in case pointer wasn't provided, allocate
    if (my_square == NULL) P
        my_square = malloc(sizeof *my_square);
        if (!my_square)
            return NULL; // or exit or whatever
    }
}

The latter is arguably the most flexible solution: if you want to work on stack, you call the function like so:

Square my_stack_square;
generate(&my_stack_square);

If you need to use heap memory, you can use:

Square *my_heap_square = generate(NULL);