简体   繁体   中英

C programming initialize 2D array dynamically

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

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.

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 .

If I want to allocate memory and initialize a board, I would:

int
main(int argc, char *argv[])
{
  int xSize, ySize;
  int **board;

  xSize = ySize = 5;

  printf("X: %u; Y: %u\n", xSize, ySize);

  board = calloc(xSize, sizeof(int *));
  printf("%p\n", board);
  int **temp = board;

  for (i = 0; i < xSize; i++)
    {
      board[i] = calloc(ySize, sizeof(int));
      printf("%d %p\n", i, board[i]);
    }
  initializeBoard (board, xSize, ySize);
  temp = board;
  for (i = 0; i < xSize; i++)
    {
      free(*temp);
      (temp)++;
    }

  free(board);

  return 0;
}

So initiliaze your board, simply do:

void
initializeBoard (int **board, int xSize, int ySize)
{
  int x, y;

printf("----\n");
  for (x = 0; x < xSize; x++)
    {
      for (y = 0; y < ySize; y++)
    {
printf("%3d", board[x][y]);
      board[x][y] = 0;
    }
printf("\n");
    }
}

In your case, use double instead of int .

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]);

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 double s 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;
}

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);         
        }     
    } 
} 

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