Two dimensional arrays and typedefs

Two-dimensional arrays can be a bit trickier than one-dimensional arrays when it comes to parameter passing, allocation, and deallocation.

The simplest approach is to think of the two-dimensional array as an 'array of arrays'. I.e. the "big array" has a bunch of rows, and each row is an array of values.

If we want to write functions to handle arbitrary numbers of rows and columns then the best approach is to use dynamic allocation of both the overall array and the individual rows.

The simplest approach is to define a new data type to represent a row, and to define our 2d array as an array of those.

In the program below we create a two-dimensional array of floats.

That means each row is an array of floats, i.e. a pointer to a float. We will use typedef to make the name ROW describe the data type float*.

The overall table will then be an array of ROWs, i.e. a ROW*.

To allocate the 2d array we allocate the array of ROWs, then go through and allocate each individual ROW within that.

As long as we keep the distinction between the ROWs as arrays of floats and the overall table as an array of ROWs everything should go smoothly!

#include <iostream>
#include <iomanip>
using namespace std;

// typedef for an array of floats
//   (used to simplify 2d array parameter passing syntax)
// the name ROW will now be synonymous with the
//   datatype  float*
typedef float* ROW;

// create a 2d array of floats, with specified number of rows and columns
// return a pointer to the allocated 2d array (null if allocation fails)
ROW *alloc(int rows, int cols);

// initialize all the cells in the 2d array
void init(ROW* t, int rows, int cols);

// print all the cells in the 2d array
void print(ROW* t, int rows, int cols);

// deallocate the dynamically allocated 2d array
void dealloc(ROW* t, int rows, int cols);

// ask the user to specify the number of rows and columns,
//     allocate and initialize the array
//     then print and delete it
int main()
{
   int rows, cols;
   cout << "Enter the desired number of rows and columns" << endl;
   cin >> rows >> cols;
   ROW *table = alloc(rows, cols);
   if (table) {
      init(table, rows, cols);
      print(table, rows, cols);
      dealloc(table, rows, cols);
   }
}

// create a 2d array of floats, with specified number of rows and columns
// return a pointer to the allocated 2d array (null if allocation fails)
ROW *alloc(int rows, int cols)
{
   // there is an array of rows, and each row
   //    consists of an array of floats
   // so first allocate the array of rows
   ROW *t = new ROW[rows];
   if (t) {
      // if that allocation succeeded, then
      //    go through and allocate each individual row
      for (int r = 0; r < rows; r++) {
          t[r] = new float[cols];
      }
   }
   // return the pointer to the overall 2d array
   return t;
}

// deallocate the dynamically allocated 2d array
void dealloc(ROW* t, int rows, int cols)
{
   // make sure the 2d array isn't null
   if (t) {
      // delete each individual row (as long as it isn't already null)
      for (int r = 0; r < rows; r++) {
          if (t[r]) delete [] t[r];
      }
      // then delete the overall array of rows
      delete [] t;
   }
}

// initialize all the cells in the 2d array
void init(ROW* t, int rows, int cols)
{
   // make sure there is actually a 2d array to initialize
   if (!t) return;

   // for each row, make sure it isn't null
   //     then initialize each column in that row
   for (int r = 0; r < rows; r++) {
       if (t[r]) {
          for (int c = 0; c < cols; c++) {
              // (here just computing an arbitrary initial value)
              t[r][c] = (r * 1) + (c * 0.01);
          }
       }
   }
}

// print all the cells in the 2d array
void print(ROW* t, int rows, int cols)
{
   // make sure there is actually a 2d array to initialize
   if (!t) return;

   // decide on an output format for the cells
   cout << fixed << setprecision(2);

   // for each row, make sure it isn't null
   //     then print each column in that row
   for (int r = 0; r < rows; r++) {
       if (t[r]) {
          for (int c = 0; c < cols; c++) {
              cout << setw(6) << t[r][c];
          }
          cout << endl;
       }
   }
}