C programming initialize 2D array dynamically

21,552

Solution 1

You are making a few mistakes in your pointers. You are passing the &dataA to init_data, so the argument type should be ***double, instead of **double. Also your first malloc is initializing an array of pointers, not an array of doubles, so it should be sizeof(double *) * dim_x. The code below should work.

void init_data(double ***data_ptr, int dim_x, int dim_y) {
  int i,j,k;
  double **data;
  data = (double **) malloc(sizeof(double *) * dim_x);
  for (k = 0; k < dim_x; k++) {
      data[k] = (double *) malloc(sizeof(double) * dim_y);
  }

  for (i = 0; i < dim_x; i++) {
      for (j = 0; j < dim_y; j++) {
          data[i][j] = ((double)rand()/(double)RAND_MAX);
      }
  }
  *data_ptr = data;
}

void main() {
  double **dataA;
  int dim = 10;
  init_data(&dataA, dim, dim);
  int i,j;
      for(i=0;i<dim;i++)
          for(j=0;j<dim;j++)
              printf("%f\n", dataA[i][j]);
}

Your first loop should also have the condition k < dim_x instead of k < dim_y. It doesn't matter in the current case since both dimensions are the same, but would cause issues if they weren't. Finally, you should use %f instead of %d in your printf, as doubles are stored in a different format than integers, and you are likely to get gibberish instead than what you want.

Solution 2

The dataA from main is never being initialized. The pointer data that you pass to init_data is immediately overwritten with a pointer returned by malloc.

Solution 3

First mistake is you are passing &dataA to the function init_data, but in the function you are receiving that value as double ** it should be double ***. Becuase you are passing pointer of a variable of type double **. So init_data function prototype should be as below

void init_data(double ***data, int dim_x, int dim_y);

Second mistake is in the below statment

data = (double **) malloc(sizeof(double) * dim_x); 

This statment should be like as below

*data = (double **) malloc(sizeof(double *) * dim_x); 

Because we have to update the pointer variable dataA. So that we will be able to display it in main function after control comes out of init_data function. And also we are going to store pointer to a double. So it should be sizeof(double *)

Update your init_data function as below

void init_data(double ***data, int dim_x, int dim_y) 

{      
    int i,j,k;
    *data = (double **) malloc(sizeof(double *) * dim_x);
    for (k = 0; k < dim_y; k++) 
    {         
        ((*data) + k) = (double *) malloc(sizeof(double) * dim_y);     
    }      

    for (i = 0; i < dim_x; i++) 
    {         
        for (j = 0; j < dim_y; j++) 
        {             
            (((*data) +i) +j) = ((double)rand()/(double)RAND_MAX);         
        }     
    } 
} 

Solution 4

You code has several problems, the majority of which could be easily identified by turning your compiler warnings up.

The first problem is that init_data expects a double** as it's first argument, however you're passing a double*** (check your compiler warnings). Since init_data is initialising memory that it's allocating itself, as opposed to initialising a block of memory that you allocated elsewhere, you could remove that first argument and return a double** instead.

You're also allocating an insufficient amount of memory for data. What you want is enough memory for dim_x amount of double*, not double. You can achieve that also with sizeof(*data) (type of *data is double*) instead of sizeof(double*).

data = malloc(sizeof(*data) * dim_x);


Since there are dim_x double*s in data and dim_y doubles in the block of memory pointed to by each of these double*s, your first loop should be iterating up to dim_x, and your second up to dim_y.

Also, casting the result of malloc (casting a void*) in C is unnecessary. There are answers on this site that will tell you why it's preferred that you don't.


Another problem has to do with the printf format specifier. %d is for int, %f is used for double (%lf when using scanf).

Now if you add code to free your allocated memory and run your program through something like valgrind, you'll see that you're no longer doing anything naughty in memory.

The working code would look like:

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

double** init_data(int dim_x, int dim_y) {
   int i,j,k;
   double **data = malloc(sizeof(*data) * dim_x); /* hoping not NULL */

   for (k = 0; k < dim_x; k++) {
      data[k] = malloc(sizeof(**data) * dim_y);   /* hoping not NULL */
   }

   for (i = 0; i < dim_y; i++) {
      for (j = 0; j < dim_y; j++) {
         data[i][j] = ((double)rand()/(double)RAND_MAX);
      }
   }
   return data;
}

int main(void)
{
   double **dataA;
   int i, j, dim = 10; 
   dataA = init_data(dim, dim);

   for(i=0; i < dim; i++)
      for(j=0; j < dim; j++)
         printf("%f\n", dataA[i][j]);

   for (i = 0; i < dim; i++)
      free(dataA[i]);
   free(dataA);

   return 0;
}

Solution 5

You are not setting the value of dataA in main().

I would change the definition of init_data to return the pointer to the new data. Something like this:

double ** init_data(int dim_x, int dim_y) {
{
int i,j,k;

double **data = (double **) malloc(sizeof(double) * dim_x);
for (k = 0; k < dim_y; k++) {
    data[k] = (double *) malloc(sizeof(double) * dim_y);
}

for (i = 0; i < dim_x; i++) {
    for (j = 0; j < dim_y; j++) {
        data[i][j] = ((double)rand()/(double)RAND_MAX);
    }
}

return data;
}

And then in main()

double **dataA = init_data(10, 10);

int i,j;
for(i=0;i<dim;i++)
    for(j=0;j<dim;j++)
        printf("%d\n", dataA[i][j]);
Share:
21,552
JDS
Author by

JDS

Updated on October 04, 2021

Comments

  • JDS
    JDS over 2 years

    I'm doing something silly here and I can't put my finger on exactly what:

     void init_data(double **data, int dim_x, int dim_y) {
    
        int i,j,k;
    
        data = (double **) malloc(sizeof(double) * dim_x);
        for (k = 0; k < dim_y; k++) {
            data[k] = (double *) malloc(sizeof(double) * dim_y);
        }
    
        for (i = 0; i < dim_x; i++) {
            for (j = 0; j < dim_y; j++) {
                data[i][j] = ((double)rand()/(double)RAND_MAX);
            }
        }
    }
    

    And in main() I do the following:

    double **dataA;
    int dim = 10; 
    init_data(&dataA, dim, dim);
    

    But then right after that when I try printing the data the program crashes:

    int i,j;
        for(i=0;i<dim;i++)
            for(j=0;j<dim;j++)
                printf("%d\n", dataA[i][j]);
    

    What am I missing?

    Thanks

  • JDS
    JDS almost 12 years
    My idea was to initialize it with that function then operate on it. Or does it not get initiated in time?
  • Chris Rice
    Chris Rice almost 12 years
    Then you need to do something like *data = malloc ...
  • JDS
    JDS almost 12 years
    Ok I think I understand now. Thank you very much