Back to DFS's C Page


TWO-DIMENSIONAL ARRAYS

Two-dimensional arrays are a little more complicated to use than one-dimensional ones. This page presents two methods of passing a pointer to a two-dimensional array to a function for processing.

Subscript Notation

Consider an int array as declared below.

#define NUM_STUDENTS 5
#define NUM_TESTS 4
int grades[NUM_STUDENTS][NUM_TESTS];

The following table illustrates how the subscripts are specified for this array, which has five (5) rows and four (4) columns.

   
0 1 2 3
0 [0][0] [0][1] [0][2] [0][3]
1 [1][0] [1][1] [1][2] [1][3]
2 [2][0] [2][1] [2][2] [2][3]
3 [3][0] [3][1] [3][2] [3][3]
4 [4][0] [4][1] [4][2] [4][3]

Array Initialization: Inline

To initialize all elements of the grades array to -1 (a number that is highly improbable for a grade), you could use a nested loop structure such as the following.

for( i = 0; i < NUM_STUDENTS; i++)
   for( j = 0; j < NUM_TESTS; j++)
      grades[i][j] = -1;

Array Initialization: At Declaration

It is also possible to initialize elements of an array at the time of its declaration. The following declaration assigns values for three grades for each of the first two students in the array. Note that the values for a specific row are enclosed within their own pair of curly brackets.

   int grades[NUM_STUDENTS][NUM_TESTS] = { {55, 60, 65},
                                           {95, 90, 85} };

It may facilitate your programming, if you keep track of how many elements in the array hold usable values. For this simple example, we can initialize two variables.

int num_students = 2;
int num_tests = 3;

Array Processing: Using Subscripts in a Function

Since, by definition, the name of any array is a pointer, we can call a function which returns the highest grade in the array as follows.

high_test = get_highest( grades, num_students, num_tests);

The second and third arguments allow the function to search only the elements which have been initialized.

One of the ways of writing get_highest() uses subscript notation:

int get_highest(int a[][NUM_TESTS], int row, int col)
/* Assumes that there is at least one element */
{
   int i, j;
   int highest = a[0][0];

   for( i = 0; i < row; i++)
      for( j = 0; j < col; j++)
         if ( a[i][j] > highest)
            highest = a[i][j];
   return highest;
}

It is necessary in this instance to specify the number of columns in the array (the number of items in a row) so that the compiler can determine the offsets from the beginning of the array. Unlike with the one-dimensional array algorithm, where we avoided comparing the first element with itself, here the extra code required does not outweigh the simplicity of the above algorithm.

Sample Program 1

This is a complete program which initializes part of an array of integer grades at the time of its declaration with 6 values and then calls a function to find, return, and print the highest grade. Note that the dimensions of the array have been changed from those used in the discussion above by altering the compiler directives.

#include <stdio.h>

#define NUM_STUDENTS 25
#define NUM_TESTS 10

int get_highest(int a[][NUM_TESTS], int row, int col);

int main()
{
   int grades[NUM_STUDENTS][NUM_TESTS] = { {55, 60, 65},
                                           {85, 90, 95} };
   int num_students = 2;
   int num_tests = 3;
   int high_test;
   
   high_test = get_highest( grades, num_students, num_tests);

   printf("The highest score is %d.\n", high_test);
   return 0;
}

int get_highest(int a[][NUM_TESTS], int row, int col)
/* Assumes that there is at least one element */
{
   int i, j;
   int highest = a[0][0];

   for( i = 0; i < row; i++)
      for( j = 0; j < col; j++)
         if ( a[i][j] > highest)
            highest = a[i][j];
   return highest;
}

Back to Top

Pointer Notation with Offset

Consider the int array as declared below. It is the same as the one discussed above except for the slight modification of the identifiers. This change was made so that we can have a second array which will be declared with different dimensions.

#define NUM_STUDENTS1 5
#define NUM_TESTS1 4
int grades1[NUM_STUDENTS1][NUM_TESTS1];

The following table illustrates the offsets of the elements from the start of this array, which has five (5) rows and four (4) columns. The italicized numbers are the subscripts for the rows and columns.

   
0 1 2 3
0 0 1 2 3
1 4 5 6 7
2 8 9 10 11
3 12 13 14 15
4 16 17 18 19

Array Initialization: Inline

To initialize all elements of the grades1 array to -1 (a number that is highly improbable for a grade), you could use a nested loop structure as was done above or do a cheat such as the following.

for( i = 0; i < NUM_STUDENTS1 * NUM_TESTS1; i++)
      *((int *)grades1 + i) = -1;

This method takes advantage of the fact that grades1 is a pointer constant for a two-dimensional array. It uses the loop control variable as the offset from the beginning of the array. The casting of the pointer constant fools the compiler into thinking that the array is one-dimensional. Since both our two-dimensional grade1 array and a one-dimensional array capable of holding 20 ints would be stored using a total of 80 consecutive bytes of RAM, no harm is done by this trickery.

Array Initialization: Generalized Using a Function

However, since the code above is array specific, we may want to generalize by creating a function which will initialize any two-dimensional array of ints.

void init_int_array(int *a, int num_rows, int num_cols)
{
   int i;

   for( i = 0; i < num_rows * num_cols; i++)
      *(a + i) = -1;
}

Here we are using the generic variable name a which is a pointer to an int. The loop control variable i is the offset into the array. The call to this function for grades1 would be:

    init_int_array( (int *)grades1, NUM_STUDENTS1, NUM_TESTS1);

Here we cast the pointer constant into a pointer to an integer, which matches the declaration in the function. The constants for the dimensions of the array are passed to init_int_array() to be used for the calculation of the total number of elements in the array.

Array Processing: Generalized Using a Function

If all of the usable data is stored in the upper left corner of the array, it is a relatively simple matter to access the appropriate elements. The following call to get_highest() sends a casted pointer to the array, the number of columns in the array, and the bounds of the upper left corner where the data is.

   high_test1 = 
      get_highest( (int *)grades1, NUM_TESTS1, num_students1, num_tests1);

The code for the function which follows illustrates the power of pointers and offsets in the C language. While we may wish to view a list of items as a number of sub-lists, the items are stored in the computer in consecutive memory locations. We can use pointer arithmetic to convert our two-dimensional perception of reality to the linear view dictated by how RAM is utilized. The four arguments passed by the function call above are sufficient for this purpose.

  1. The pointer constant grades1 provides the array's starting point in RAM.
  2. NUM_TESTS1 provides the maximum number of possible items in the sub-list.
  3. num_students1 provides the number of rows to be checked.
  4. num_tests1 provides the number of columns to be checked.

The following expression can be used to access an element of the array.

  *(a + i*cols + j)
  1. a, which remains constant, points at the zeroth element of the list.
  2. cols, which remains constant, is the number of columns in a row.
  3. i ranges from 0 to one less than the number of rows to be searched.
  4. j ranges from 0 to one less than the number of columns to be searched.

With a remaining constant, it can be seen that i*cols + j provides the offset from the beginning of the list.

Here is a complete function which can be used to return the largest int in a portion of a two-dimensional array of any size.

int get_highest(int *a, int cols, int row, int col)
/* Assumes that the elements with usable values are
   in the upper left corner of the array as 
   delimited by row and col;
   cols is the number of columns in the array passed */
{
   int i, j;
   int highest = *a;

   for( i = 0; i < row; i++)
      for( j = 0; j < col; j++)
         if ( *(a + i*cols + j) > highest)
            highest = *(a + i*cols + j);
   return highest;
}

Sample Program 2

This is a program which initializes parts of two arrays of integer grades at the time of their declaration, each with 6 values. Then it calls a function to find, return, and print the highest grade in each of the two arrays.

#include <stdio.h>

#define NUM_STUDENTS1 25
#define NUM_TESTS1 10
#define NUM_STUDENTS2 15
#define NUM_TESTS2 8

int get_highest(int *a, int cols, int row, int col);

int main()
{
   int grades1[NUM_STUDENTS1][NUM_TESTS1] = { {55, 60, 65},
                                              {85, 90, 95} };
   int num_students1 = 2;
   int num_tests1 = 3;
   int high_test1;

   int grades2[NUM_STUDENTS2][NUM_TESTS2] = { {55, 60},
                                              {85, 90},
                                              {75, 70} };
   int num_students2 = 3;
   int num_tests2 = 2;
   int high_test2;
   
   high_test1 = 
      get_highest( (int *)grades1, NUM_TESTS1, num_students1, num_tests1);
   printf("The highest score in the first class is %d.\n", high_test1);

   high_test2 = 
      get_highest( (int *)grades2, NUM_TESTS2, num_students2, num_tests2);
   printf("The highest score in the second class is %d.\n", high_test2);

   return 0;
}

int get_highest(int *a, int cols, int row, int col)
/* Assumes that the elements with usable values are
   in the upper left corner of the array as 
   delimited by row and col;
   cols is the number of columns in the array passed */
{
   int i, j;
   int highest = *a;

   for( i = 0; i < row; i++)
      for( j = 0; j < col; j++)
         if ( *(a + i*cols + j) > highest)
            highest = *(a + i*cols + j);
   return highest;
}

Back to Top


Created 12 Jan 1999
Modified 15 Jan 1999
© DFStermole 1999