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.
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] |
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;
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;
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.
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;
}
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 |
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.
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.
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.
The following expression can be used to access an element of the array.
*(a + i*cols + j)
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;
}
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;
}