Multi-dimensional arrays can be built dynamically using
  pointers-to-pointers with malloc. In the example below, a single
  pointer-to-pointer-to-int is declared. Upon declaration, the
  pointer has no meaningful value. A call to mallac then requests
  that the pointer point to a block of nx valid memory units:
x =  (int **) malloc(nx * sizeof(int *));
After this call, x now has a valid value; specifically, the
  beginning address of a block of memory which contains nx
  pointers-to-int. Eachof these pointers to int is just a regular
  pointer, as we have seen many times. They have yet to be
  initialized to anything meaningful, and the can each be accessed
  as either 
x[0], x[1] ... x[nx-1], OR *x, *(x+1), *(x+2),
  ... *(x+nx-1).
To give eachof these pointers a meaningful value,
  we can call malloc for each of them, such as is accomplished by
  this loop:
 for (i=0;i<nx;++i){
    x[i] = ( int * ) malloc( ny * sizeof(int));
  }
Note that we could have also said:
for (i=0;i<nx;++i){
    *(x+i) = ( int * ) malloc( ny * sizeof(int));
  }
Now that each pointer in our array of pointers points to a
  meaningful block of memory (each of size ny ints), we can assign
  values. To understand how values are assigned, consider the
  schematic below. You will need to study this very carefully until
  it is very clear what is going on. This can be a little tricky but
  once you get the hang of it it's not so bad.
  x[0] --->   | *x[0] | *x[0]+1 | *x[0] + 2 | ... | *x[0]+ny-1 |
  x[1] --->   | *x[1] | *x[1]+1 | *x[1] + 2 | ... | *x[1]+ny-1 |
  .
  .
  .
  x[nx-1] ---> | *x[nx-1] | *x[nx-1]+1 | *x[nx-1] + 2 | ... | *x[nx-1]+ny-1 |
This is equivalent to:  
  x[0] --->   | *(*(x+0)+0) | *(*(x+0)+1) | *(*(x+0)+2) | ... | *(*(x+0)+ny-1) |
  x[1] --->   | *(*(x+1)+0) | *(*(x+1)+1) | *(*(x+1)+2) | ... | *(*(x+1)+ny-1) |
  .
  .
  .
  x[nx-1] --->   | *(*(x+nx-1)+0) | *(*(x+nx-1)+1) | *(*(x+nx-1)+2) | ... | *(*(x+nx-1)+ny-1) |
And this is equivalent to:
  x[0] --->   | x[0][0] | x[0][1] | x[0][2] | ... | x[0][ny-1] |
  x[1] --->   | x[1][0] | x[1][1] | x[1][2] | ... | x[1][ny-1] |
  .
  .
  .
  x[nx-1] ---> | x[nx-1][0] | x[nx-1][1] | x[nx-1][2] | ... | x[nx-1][ny-1] |
... given the important relation:
 *( *(x + i) + j) = *( x[i] + j) = x[i][j]