Home C++ Introduction Decisions Loops Input/Output Functions Stack and Heap References Arrays Searching and Sorting Recursion Pointers Character and Strings Structures Classes Inheritance Exceptions Templatess STL Modern C++ Misc Books ----

Two Dimensional Arrays


Contents



Introduction

See full image


The above picture shows a double pointer being used as a 2 dimensional
array. We have a double pointer that can be declared as:

  int** DoublePointer ;

Now if we do a *DoublePointer we will end up at the beginning of the
block with address 100 and a value inside it. In this case we have a
block so "*(DoublePointer+1)" will lead us to the element of 101. We
can also use array notation and get at the values using :

     DoublePointer[0]    and DobulePointer[1]

These are the rows of our 2 dimensional array. Now each pointer points
to a block of memory and if we follow the "DoublePointer[0]" and say

*(DoublePointer[0])

That will give us the first element of the block in RAM . We can
also write the above as:

DoublePointer[0][0]

This is how we can construct a 2 dimensional array dynamically. Ex:


File: two1.cpp
#include <iostream>

using namespace std ;

int main()
{
    int** TwoDimArray ;
    const int ROW_COUNT = 2 ;
    const int COL_COUNT = 3 ;
    TwoDimArray = new int*[ROW_COUNT] ;


    for(int i1=0 ,  k1=1 ;        i1<ROW_COUNT ;    i1++   )
    {
        TwoDimArray[i1] =  new int[COL_COUNT] ;
        for( int j1=0 ; j1<COL_COUNT ; j1++ )
        {
            TwoDimArray[i1][j1] = k1++ ;
        }
    } //for

    //print contents using array notation

    for(int i1=0  ;        i1<ROW_COUNT ;    i1++  )
    {
        for( int j1=0 ; j1<COL_COUNT ; j1++ )
        {
            cout << TwoDimArray[i1][j1] << " "  ;

        }
        cout << endl ;

    } //for

    cout << endl << endl ;

    //print contents using pointer notation

    for(int i1=0   ;        i1<ROW_COUNT ;    i1++  )
    {
        for( int j1=0 ; j1<COL_COUNT ; j1++ )
        {
            cout << (   *( (*(TwoDimArray+i1)) + j1 )  ) << " "  ;
        }

        cout << endl ;

    } //for

    cout << endl << endl ;



    for(int i1=0  ;  i1<ROW_COUNT ;    i1++   )
    {
        delete[]  TwoDimArray[i1]     ;
    }
    delete[]   TwoDimArray  ;



    return 0 ;
}
Output:
1 2 3
4 5 6
1 2 3
4 5 6
Constructing a 2 dimensional array using the C notation:
File: two2.cpp
#include <iostream>
using namespace std ;

int main()
{
    int** TwoDimArray ;
    const int ROW_COUNT = 2 ;
    const int COL_COUNT = 3 ;
    TwoDimArray = (int**)malloc(sizeof(int*)*ROW_COUNT)  ;

    for(int i1=0 ,  k1=1 ;        i1<ROW_COUNT ;    i1++   )
    {
        TwoDimArray[i1] =  (int*)  malloc(sizeof(int)*COL_COUNT)  ;
        for( int j1=0 ; j1<COL_COUNT ; j1++ )
          {
              TwoDimArray[i1][j1] = k1++ ;
          }
    } //for

    //print contents using array notation
    for(int i1=0  ;        i1<ROW_COUNT ;    i1++  )
    {
        for( int j1=0 ; j1<COL_COUNT ; j1++ )
         {
             cout << TwoDimArray[i1][j1] << " "  ;
         }
         cout << endl ;
    } //for

    cout << endl << endl ;

    //print contents using pointer notation

    for(int i1=0   ;        i1<ROW_COUNT ;    i1++  )
    {
        for( int j1=0 ; j1<COL_COUNT ; j1++ )
          {
              cout << (   *( (*(TwoDimArray+i1)) + j1 )  ) << " "  ;
          }
         cout << endl ;
    } //for

    cout << endl << endl ;



    for(int i1=0  ;        i1<ROW_COUNT ;    i1++   )
    {
        free(  TwoDimArray[i1] )    ;
    }

    free(   TwoDimArray ) ;



}


Output:
1 2 3
4 5 6
Exercises
1) What's wrong with the following program:

Passing arrays and pointers to functions


File: ptr2.cpp
#include <iostream>
using namespace std ;



void function1( int arr2[] )
{
 arr2[0] = 100 ;
}



void printArray( int arr1[] , int size )
{
    for( int i1=0 ; i1<size ; i1++ )
    {
        cout << arr1[i1] << " " ;
    }

    cout << endl ;
}



int main()
{
    int arr1[] = { 10, 20, 30 } ;
    function1( arr1 ) ;
    printArray( arr1, 3 ) ;
    return 0 ;

}

Array and pointers are almost the same in that they both contain an address. If we pass an array as an argument to a function and the function changes something in the array then that change is reflected in the calling function. Same behavior is exhibited when we pass a pointer to a function and the function manipulates the value the pointer points to.
File: ptr3.cpp
#include <iostream>
using namespace std ;

void function1( int arr1[] )
{
 cout << "function1:" << arr1[0] << endl ;
}

void function2( int* arr1 )
{
 cout << "function2:" << arr1[0] << endl ;
}

void function3( int arr1[][3] )
{
 cout << "function3:" << arr1[0][0] << endl ;
}

void function4( int** arr1 )
{
  cout << "function4:" << arr1[0][0] << endl ;
}

int main()
{
 //Single Dimensional Arrays
  int array1[10] = { 1,2,3,4,5,6,7,8,9,10} ;
  function1( array1 ) ;
  //Ok to pass an array to a pointer
   function2( array1 ) ;
   int* ptr1 = new int[10] ;
   ptr1[0] = 1 ; ptr1[1] = 2 ;
   //Ok to pass a pointer to an array
   function1( ptr1 ) ;
   function2(  ptr1 ) ;

   //Two Dimensional Arrays
   int array2[2][3]  = {  {1,2,3} , {4,5,6} } ;
   int** TwoDimArray ;
   const int ROW_COUNT = 2 ;
   const int COL_COUNT = 3 ;

   TwoDimArray = (int**)malloc(sizeof(int*)*ROW_COUNT)  ;
   for(int i1=0 ,  k1=1 ;        i1<ROW_COUNT ;    i1++   )
   {
        TwoDimArray[i1] =  (int*)  malloc(sizeof(int)*COL_COUNT)  ;
        for( int j1=0 ; j1<COL_COUNT ; j1++ )
         {
           TwoDimArray[i1][j1] = k1++ ;
        }
   } //for

           function3( array2 ) ;
           //  Compiler error    //
           function4(  array2 ) ;
           //  Compiler error
           //function3( TwoDimArray ) ;
           function4( TwoDimArray ) ;
           return 0 ;
}


Output:
function1:1
function2:1
function1:1
function2:1
function3:1
function4:1
The above code illustrates how single and two dimensional
arrays can be passed to functions. With a single dimensional
array we can pass an array variable to a function taking
an array argument or a pointer argument. After all arrays
and pointers hold addresses and we should be able to use
either one.

The declarations for "functions1" and "function2" are:

void function1( int arr1[] )

void function2( int* arr1 )

We are passing the below to both the functions:

    int array1[10] = { 1,2,3,4,5,6,7,8,9,10} ;

      function1( array1 ) ;

    //Ok to pass an array to a pointer

       function2( array1 ) ;

    int* ptr1 = new int[10] ;

    ptr1[0] = 1 ; ptr1[1] = 2 ;

    //Ok to pass a pointer to an array

    function1( ptr1 ) ;

    function2(  ptr1 ) ;

In the first case we have an array variable and we can
pass it to both the functions and in the second case we
have a pointer that we can pass to both functions .
The code compiles and the first element in the block
is printed in both cases.

Now we have the 2 dimensional array case:

void function3( int arr1[][3] )
{
     cout << "function3:" << arr1[0][0] << endl ;
}

void function4( int** arr1 )
{
    cout << "function4:" << arr1[0][0] << endl ;
}

We can see that the notation to access the 2 dimensional
arrays is the same "arr1[0][0]" . So we expect the
functions to take either a 2 dimensional array or a
double pointer. But that is not the case.

    function3( array2 ) ;

   //  Compiler error

   //    function4(  array2 ) ;

    //  Compiler error

   //function3( TwoDimArray ) ;

    function4( TwoDimArray ) ;

If we try to pass a 2 dimensional array to a double pointer
then we receive a compiler error and if we try to pass a
double pointer to a 2 dimensional array then also we receive
a compiler error. Why does the compiler not allow the
conversion. To understand this we need to understand how
the 2 types are stored in RAM.

    int array2[2][3]  = {  {1,2,3} , {4,5,6} }    ;

    int** TwoDimArray   ;

                 RAM

 array2     0     100

           100    1

                     2

                     3

                     4

                    6

                         RAM

TwoDimArray      0       100

          100    Address of first  row

          200    Address of second row

If we have a 2 dimensional array then we  the elements are
stored in a linear fashion. We must know the number of
columns in order to find out when the rows start. However
with a double pointer we store a block of addresses and
not the actual elements .

We follow the address to the block and then grab the
elements from the block. If

function4(  array2 ) ;

did compile then things will not work as expected.
Remember "array2" is actually a 2 dimensional array.

Then function4 converts it to a double pointer and then we
do arr1[0][0] .

Now the first "arr1[0]" gives us the element "1" but the
argument was a double pointer. Now the compiler is going
to go to the block with the memory address of "1" .
However "1" is the actual element and not an address.
We cannot convert between a legitimate 2 dimensional array
and a double pointer. Compiler is going to get confused
because they store things in a different fashion in the RAM.