简体   繁体   中英

How to malloc a 2d jagged array using a pointer passed by reference to a function in C

I have a 2D jagged array declared in my main() block. This is to be passed to a function to have memory allocated to it. The following is the most reduced case which compiles but crashes when it runs. Where am I going wrong?

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

void alloc2d(double ***p);


int main () {

    double **data;

    alloc2d(&data);
    printf("Before assign to data\n");
    data[0][0] = 0.1;
    printf("After assign to data\n");
    free(data);
}


void alloc2d(double ***p) {

    int i, n, m;

    // Get some dynamically assigned sizes
    printf("Enter size: ");
    scanf("%d %d", &n, &m);    
    // Now allocate
    *p = malloc(n * sizeof(double*));
    for (i = 0; i < n; i++) {
        *p[i] = malloc(m * sizeof(double));
    }
    printf("End of alloc2d\n");
}

This reads the values but crashes when I enter low numbers (ie '1 1') but crashes when I enter high numbers (ie '10 10').

You made a very simple syntax error

*p[i] = (double*)malloc(m * sizeof(double));

should really be

(*p)[i] = (double*)malloc(m * sizeof(double));

This is because in C, [] operator has higher precedence than *. So when you type *p[i] , it is translated into **(p + i) .

This means: you are asking the compiler to calculate the address by offsetting the address of p by i * sizeof(double**) , which is clearly not what you actually want.

So, in order to force the compiler to dereference p first, simply surroud *p with brackets.

Operator precedence is the answer. *p[i] is equivalent to *(p[i]) . This makes you access memory that lies right after the data pointer, which will either corrupt some other variables on the stack, or crash completely.

You were looking for (*p)[i] , which will be the i-th entry in the newly allocated array.

What your alloc2d() allocates is not really a 2D array, but:

  • 1 1D n-long array of pointers to double
  • n 1D m-long arrays of doubles

Multi-dimensional arrays in C are only possible, if all but the last of the dimensions are known at compile-time:

double a[5][11];

Maybe, this program can help you understand... Note, how COLUMNS is a compile-time constant, even if rows is a run-time variable:

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

typedef double  myrow_t[11]; /* 11 columns */
#define COLUMNS (sizeof(myrow_t)/sizeof(double))

static unsigned
alloc2d(myrow_t **pd)
{
unsigned int rows;

printf("Enter the number of rows: ");
while (scanf("%u", &rows) != 1)
    printf("\ninvalid input, please, try again: ");

*pd = malloc(rows * sizeof(**pd));
if (*pd == NULL)
    err(EX_TEMPFAIL, "Out of memory");

return rows;
}

int
main()
{
myrow_t     *d;
unsigned int     row, column, rows;

rows = alloc2d(&d);

for (row = 0; row < rows; row++)
    for (column = 0; column < COLUMNS; column++)
        d[row][column] = row * column;

for (row = 0; row < rows; row++) {
    printf("Row %3d:\t", row);
    for (column = 0; column < COLUMNS; column++)
        printf("%.0f\t", d[row][column]);
    puts("");
}

free(d);
return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM