/*
   This program demonstrates how C (and C++) have two different kinds
   of two-dimensional arrays. One kind we will refer to as an "array
   of rows" (AoR) and the other kind we will refer to as an "array
   of pointers to rows" (AoP). An "array of rows" is what you get
   when declare an automatically allocated two-dimensional array and
   an "array of pointers to rows" is what you need when you want a
   dynamically allocated two-dimensional array.

   In short, we can summarize the following discussion by saying that
   C (and C++) does not really have any notion of two-dimensional arrays.
   The C language only has one-dimensional arrays! All higher dimensional
   arrays are build up out of one-dimensional arrays.

   This program also demonstrate how to define functions that can accept
   as a parameter arbitrarily sized two-dimensional arrays. We will define
   one function that accepts an arbitrary "array of rows" and another
   function that accepts an arbitrary "array of pointers to rows".


   Consider a 3 by 4 "array of rows" of int's, that is an array with
   3 rows and 4 columns. To the C compiler, this is considered to be a
   one-dimensional array of length 3 whose cells are one-dimensional
   integer arrays of length 4 (i.e., an array of arrays). The whole
   array is allocated in memory as 12 consecutive int's, much like a
   one-dimensional integer array of length 12.

   In other words, the declaration        int[][4]    ____  __myArray[0]
       int myArray[3][4];                 myArray~~~~|    |
   declares myArray to be a                          |____|
   one-dimensional array with 3 cells,               |    |
   each cell of type int[4],                         |____|
   i.e., another one-dimensional array.              |    |
   In a certain sense,                               |____|
       int myArray[3][4];                            |    |
   should be equivalent to                           |____| __myArray[1]
       int[4]  myArray[3];                           |    |
   but the latter is not valid C                     |____|
                                                     |    |
                                                     |____|
                                                     |    |
                                                     |____|
                                                     |    |
                                                     |____| __myArray[2]
                                                     |    |
                                                     |____|
                                                     |    |
                                                     |____|
                                                     |    |
                                                     |____|
                                                     |    |
                                                     |____|
                                                   int[3][4]


   On the other hand, a 3 by 4 "array of pointers to rows" is made up of
   four separate one-dimensional arrays. First, there is a one-dimensional
   array of length 3 whose cells are pointers to one-dimensional arrays of
   int's (i.e., the cells are of type int*). Then there are three one-
   dimensional arrays, each of length 4, whose cells are integers. Each of
   the three pointers in the first array point to one of the three integer
   arrays of length 4. The three integer arrays of length 4 are the actual
   "rows" of the array. The single array of length 3 of integer pointers
   is sometimes called the "array of rows".

   Here is a specific example of how to construct (allocate) such an
   "array of pointers to rows".

      int** myArray;
      myArray = (int**)( calloc(3, sizeof(int*)) );
      for (i = 0; i < 3; i++)
         myArray[i] = (int*)( calloc(4, sizeof(int)) );

   Here is an illustration of how this two-dimensional array is put together
   in memory. Notice that is built entirely out of one-dimensional arrays!

            int**     int*[3]
            ____       ____                       ____
    myArray|    |~~~~>|    |~~~~~~~~~~~~~~~~~~~~>|    |
           |____|     |____|             ____    |____|
                      |    |~~~~~~~~~~~>|    |   |    |
                      |____|    ____    |____|   |____|
                      |    |~~>|    |   |    |   |    |
                      |____|   |____|   |____|   |____|
                               |    |   |    |   |    |
                               |____|   |____|   |____|
                               |    |   |    |   int[4]
                               |____|   |____|
                               |    |   int[4]
                               |____|
                               int[4]


   Even though the above two kinds of two-dimensional arrays have very
   different structures, for both kinds of structure, the array notation
   myArray[i][j] works! It is a very good exercise in understanding pointers
   to figure out precisely how the notation myArray[i][j] is interpreted in
   each case.

   First of all, in both cases, the notation a[i][j] is equivalent to the pointer
   notation *(*(a+i)+j) (this is because C defines the bracket notation
   b[k] to mean *(b+k) ). The notation a[i][j] is also equivalent to
   *(a[i]+j) and to (*(a+i))[j].

   As an aside, notice that in C, the two expressions
      myArray[i]
      i[myArray]
   have exactly the same meaning, and both are valid in a C program (try it).


   So for an "array of rows", what does *(*(a+i)+j) mean? First, a is the
   address of the first cell in an array of rows. Then a+i means do pointer
   arithmetic to calculate the address of the i'th cell in this array, that
   is, a+i gives the address of the beginning of the i'th row. (Because of
   the data type of a, the +i in a+i means add i multiples of the size of
   one row.) Then *(a+i) dereferences this address to be an address of an
   int. Then *(a+i)+j means do pointer arithmetic to find the address of the
   j'th cell in the row pointed to by a+i (the +j means add j multiples of
   the size of one int). Then *(*(a+i)+j) dereferences the address of the
   j'th cell in the i'th row to return an integer.

   Now, for an "array of pointers to rows", what does *(*(a+i)+j) mean?
   First, a is the address of the first cell in an array of integer pointers.
   Then a+i means do pointer arithmetic to calculate the address of the
   i'th cell in this array, that is, a+i gives the address of the i'th
   pointer in the array of pointers. (Because of the data type of a, the
   +i in a+i means add i multiples of the size of an integer pointer.) Then
   *(a+i) dereferences this pointer to get the address of a one dimensional
   array of integers. Then *(a+i)+j means do pointer arithmetic to find the
   address of the j'th cell in the one dimensional array pointed to by the
   contents of a+i (the +j means add j multiples of the size of an int). Then
   *(*(a+i)+j) dereferences the address of the j'th cell in the i'th one
   dimensional integer array to return an integer.

   Notice that the key idea in understanding the difference between
   *(*(a+i)+j) for an array of rows and *(*(a+i)+j) for an array of pointers
   to rows is the idea of pointer arithmetic. In the two different cases,
   the a+i represents two different kinds of pointer arithmetic (but in both
   cases the +j represents the same kind of pointer arithmetic).

   Finally, we should ask, how does the compiler know which way to compile the
   expression myArray[i][j]? How does the compiler know whether to use the
   array of rows interpretation or the array of pointers to rows interpretation?
   The answer is that the compiler looks to see how the variable myArray was
   declared. If myArray has the type of a pointer to a pointer (say int**)
   then myArray[i][j] is compiled as accessing an array of pointers to rows.
   If myArray has type int[][COLM], where COLM is a compile(!) time constant,
   then myArray[i][j] is compiled as accessing an array of rows (this has
   important implications for defining a function that has an array of rows
   as one of its parameters). It worth pointing out that if myArray has the
   type of a pointer (say int*) , then the compiler cannot compile the notation
   myArray[i][j] because the compiler has no idea what the size of a row is.

   As an exercise, in the main() function below, declare, create, and
   initialize a dynamic two dimensional array of rows. How is this
   different from the automatic 2d array of rows? Try passing this
   array to the function print2dAoR().

   Also, try declaring and initializing an automatic 2d array
   of pointers to rows. Can this be done? Why or why not.

   You may also want to read the following web pages:
      http://c-faq.com/aryptr/dynmuldimary.html
      http://www-ee.eng.hawaii.edu/~tep/EE150/book/chap9/section2.1.2.html
*/
#include <stdio.h>   // for printf()
#include <stdlib.h>  // for calloc()


// Prototypes for two functions that accept arbitrary two dimensional
// arrays. The first accepts arrays of pointers to rows (AoP) and the
// second accepts arrays of rows (AoR).
void print2dAoP(int *a[], int row, int col);
void print2dAoR(int  a[], int row, int col);


int main()
{
   int i, j;

   // These constants are needed for the automatic arrays.
   #define ROW_SIZE  4
   #define COL_SIZE  5

   // These variables can be used with the dynamic arrays.
   int row_size = 4;
   int col_size = 5;

   // Demonstrate how to declare and initialize a
   // two dimensional automatic array as an array of rows.
   int my2dAoRAuto_1[][COL_SIZE] = { {21, 22, 23, 24, 25},
                                     {26, 27, 28, 29, 30},
                                     {31, 32, 33, 34, 35},
                                     {36, 37, 38, 39, 40} };

   // Or, separately declare a two dimensional automatic array
   // as an array of rows...
   int my2dAoRAuto[ROW_SIZE][COL_SIZE];

   // and then initialize the array (and demonstrate six
   // different ways to access the cells of the array).
   for (i = 0; i < ROW_SIZE; i++)
      for (j = 0; j < COL_SIZE; j++)
      {
         // Access the elements of the array six different ways.
               my2dAoRAuto[i][j]              = 200+10*i+j;
             *(my2dAoRAuto[i]+j)              = 200+10*i+j;
            (*(my2dAoRAuto+i))[j]             = 200+10*i+j;
           *(*(my2dAoRAuto+i)+j)              = 200+10*i+j;
            *(&my2dAoRAuto[0][0]+i*COL_SIZE+j)= 200+10*i+j;
       *((int*)my2dAoRAuto+i*COL_SIZE+j)      = 200+10*i+j;
//           *(my2dAoRAuto+i*COL_SIZE+j)      = 200+10*i+j;  // doesn't compile
      }


   // Declare a two dimensional dynamic array variable
   // as an array of pointers to rows (i.e., a pointer to a pointer).
   int **my2dAoPDyn;

   // Dynamically create the (one dimensional) array of pointers
   // to rows (i.e., an array of pointers to int).
   my2dAoPDyn = (int**)calloc( row_size, sizeof(int*) );

   // Dynamically create each of the (one dimensional) rows
   // (this initializes the array of pointers to rows).
   for (i = 0; i < row_size; i++)
      my2dAoPDyn[i] = (int*)calloc( col_size, sizeof(int) );

   // Initialize the rows of this array (and demonstrate five
   // different ways to access the cells of the array).
   for (i = 0; i < row_size; i++)
      for (j = 0; j < col_size; j++)
      {
         // Access the elements of the array four different ways.
             my2dAoPDyn[i][j]              = 10+10*i+j;
           *(my2dAoPDyn[i]+j)              = 10+10*i+j;
          (*(my2dAoPDyn+i))[j]             = 10+10*i+j;
         *(*(my2dAoPDyn+i)+j)              = 10+10*i+j;
//        *(&my2dAoPDyn[0][0]+i*COL_SIZE+j)= 10+10*i+j;  // compiles, but does not do what we want!
//   *((int*)my2dAoPDyn+i*COL_SIZE+j)      = 10+10*i+j;  // compiles, but does not do what we want!
      }

   // Print the dynamic array of pointers to rows.
   print2dAoP(my2dAoPDyn, row_size, col_size);

   printf("\n");

   // print the first (automatic) array of rows
   print2dAoR((int*)my2dAoRAuto_1, ROW_SIZE, COL_SIZE);

   printf("\n");

   // print the second (automatic) array of rows
   print2dAoR((int*)my2dAoRAuto, ROW_SIZE, COL_SIZE);

   return 0;
}


/*
   The following function prints out a two dimensional array of
   arbitrary dimension that is structured as an array of pointers
   to rows.
*/
//void print2dAoP(int **a,   int row, int col)  // another way to declare the function
void print2dAoP(int  *a[], int row, int col)
{
   int i,j;

   for (i = 0; i < row; i++)
   {
      for (j = 0; j < col; j++)
      {
         // Access the elements of the array four different ways.
         printf( "%d ", a[i][j] );
         printf( "%d ", *(a[i]+j) );
         printf( "%d ", (*(a+i))[j] );
         printf( "%d ", *(*(a+i)+j) );
         // Note: The following compiles, but it is wrong. Why?
         //printf( "%d ", *(a+i)[j] );
      }
      printf("\n");
   }
}


/*
   The following function prints out a two dimensional array of
   arbitrary dimension that is structured as an arrays of rows.
   The 2d array can be declared as either an automatic or a
   dynamic array.

   Notice that, as far as I know, there is no way to get this
   function to use the usual notation for 2d arrays, i.e., a[i][j].
   This is because there is no way to let the compiler know at
   compile time what the size of a row is, so the compiler cannot
   do the proper pointer arithmetic in *(*(a+i)+j) (specifically,
   it can't do a+i).

   Basically, what this function does is treat the array of rows as a
   one dimensional integer array of size row*col, and then the function
   does its own "index calculation" to find a[i][j].

   Notice that, for this to work, the caller of this function must(!)
   cast the input array to type int* (from type int[][COL_SIZE]).
*/
//void print2dAoR(const int* a, int row, int col)  // another way to declare the function
void print2dAoR(int a[], int row, int col)
{
   int i,j;

   for (i = 0; i < row; i++)
   {
      for (j = 0; j < col; j++)
      {
         // Access the elements of the array two different ways.
         printf( "%d ", a[i*col+j] );
         printf( "%d ", *(a+i*col+j) );
      }
      printf("\n");
   }
}