Multidimensional Arrays

C does not technically support multidimensional arrays. However, we can define an array or arrays, which accomplished the same thing.

#define MAX_ROWS    100
#define MAX_COLS    100

double  coefficients[MAX_ROWS][MAX_COLS];
        

Statically sized 1-dimensional arrays are wasteful enough, but the waste increases by an order of magnitude with each dimension we add, so this is generally a bad practice unless the maximum matrix size is small.

The key to conserving memory with matrices is hidden in plain view in the argv[] array received by main();

int     main(int argc, char *argv[])
        

The argv[] array is essentially a 2-dimensional array of characters. We can use the same concept for any 2-dimensional array.

TBD: Graphic of a pointer array

To implement a pointer array, we first allocate a 1-dimensional array of pointers to the data type contained in the matrix.

Each of these pointers will point to a 1-dimensional array of values representing a row in the matrix.

/***************************************************************************
 *  Description:
 *      Read a matrix into a pointer array and print it out to verify.
 *
 *  History: 
 *  Date        Name        Modification
 *  2017-08-25  Jason Bacon Begin
 ***************************************************************************/

#include <stdio.h>
#include <sysexits.h>
#include <stdlib.h>

typedef double  real_t;

int     main(int argc,char *argv[])

{
    size_t  rows, cols, r, c;
    real_t  **matrix;
    
    printf("Rows? ");
    scanf("%zu", &rows);
    printf("Cols? ");
    scanf("%zu", &cols);
    
    /* Allocate pointer array */
    matrix = (real_t **)malloc(rows * sizeof(real_t *));
    
    /*
     *  Read matrix data separated by whitespace.  Well-formatted input
     *  will have a newline after each row.
     */
    for (r = 0; r < rows; ++r)
    {
        matrix[r] = (real_t *)malloc(cols * sizeof(real_t));
        for (c = 0; c < cols; ++c)
            scanf("%lf", &matrix[r][c]);
    }

    /* Print matrix one row per line. */
    for (r = 0; r < rows; ++r)
    {
        for (c = 0; c < cols; ++c)
            printf("%5.2f", matrix[r][c]);
        putchar('\n');
    }
    
    /* Free the arrays */
    for (r = 0; r < rows; ++r)
        free(matrix[r]);
    free(matrix);
    
    return EX_OK;
}

2 3
2.0 4.3 1.0
9.7 4.7 8.2

In Fortran, we store matrix data in a multidimensional array. Defining multidimensional arrays is done much like one-dimensional arrays. We add more dimensions separated by commas:

        double precision :: coefficients(1:MAX_ROWS, 1:MAX_COLS)
        

Note that as the number of dimensions increases, so does the potential for memory waste if the array size is larger than needed. If we use 50 elements in an array of 100, half the array is wasted. If we store a 50x50 matrix in a 100x100 array, 3/4 of the memory (7,500 elements) is wasted. If we store a 50x50x50 brick in a 100x100x100 array, 7/8 of the memory (875,000 elements) is wasted. Therefore, using dynamic memory allocation becomes increasingly important as the number if dimensions grows.

        double precision, allocatable :: coefficients(:, :)
        integer :: rows, cols
        
        read *, rows, cols
    
        allocate(matrix(1:rows, 1:cols), stat=allocate_status)
        
        if ( allocate_status /= 0 ) then    
            print *, 'Error: Unable to allocate ', rows, ' x ', cols, &
                ' matrix.'
            stop
        endif
        

Working with multidimensional arrays will always involve a nested loop, i.e. a loop inside a loop. In Fortran, the outer loop should traverse the columns, and the inner loop should traverse the rows. The reason for this is explained in the section called “Importance of Traversal Order”.