0

I have a 3D double array initialised as such in driver.h:

extern double ***grid;

I would like to set its values in driver.c:

double ***grid;
grid = calloc(cells_x * cells_y * cells_z, sizeof(double)); 
grid[0][1][2] = 123;

However, valgrind gives "Invalid read of size 8" error. What am I doing wrong?

Darbininkai Broliai
  • 159
  • 1
  • 1
  • 13

1 Answers1

5

Your code is declaring an array of pointers to pointer (three-asterisk array) while the assignment places a pointer to a single block of size cells_x * cells_y * cells_z into it. This is incorrect, because the users of your extern variable expect a "jagged" array (i.e. an array of pointers to pointer):

static double*** initGrid(size_t cells_x, size_t cells_y, size_t cells_z) {
    double ***grid;
    grid = malloc(cells_x, sizeof(double**));
    for (size_t x = 0 ; x != cells_x ; x++) {
        grid[x] = malloc(cells_y, sizeof(double*));
        for (size_t y = 0 ; y != cells_y ; y++) {
            grid[x][y] = calloc(cells_z, sizeof(double));
        }
    }
    return grid;
}
static void freeGrid(double ***grid, size_t cells_x, size_t cells_y) {
    for (size_t x = 0 ; x != cells_x ; x++) {
        for (size_t y = 0 ; y != cells_y ; y++) {
            free(grid[x][y]);
        }
        free(grid[x]);
    }
    free(grid);
}

You need to allocate and free jagged array in a different way - with multiple loops, or declare your grid as a pointer to an array of arrays.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • Thank you very much! That worked (with the mallocs being cells_x * sizeof). If you have some time, maybe you could show me how to then place this in a function so as to "hide" all this stuff in a separate file for example, and only call something like initGrid(grid, cells_x, cells_y, cells_z) in the main method? – Darbininkai Broliai Jul 17 '16 at 12:26
  • @DarbininkaiBroliai Sure - I edited to make functions to initialize and free the grid. Initialization function returns a pointer, rather than setting it, because I think taking a four-asterisk pointer (you'd have to pass `&grid` for modification to be possible) as a parameter would be too much. – Sergey Kalinichenko Jul 17 '16 at 12:52