#include <stdio.h>
#include <stdlib.h>

typedef int** Matrix; /* hide the int** data type */

void
  store( char* file, Matrix m1, Matrix m2, int n ),
  mult( Matrix m1, Matrix m2, Matrix m3, int n ),
  print( Matrix m, int n ),
  freeMatrix( Matrix m, int n );
Matrix createMatrix( int n );

main()
{
  int n;
  char filename[ FILENAME_MAX ];
  Matrix m1, m2, m3;

  /* prompt user for side and file name */
  printf( "Matrix side and file name: " );
  scanf( "%d %s", &n, filename );

  /* create the matrices */
  m1 = createMatrix( n );
  m2 = createMatrix( n );
  m3 = createMatrix( n );
  if ( NULL == m1 || NULL == m2 || NULL == m3 ) {  /* success? */
    fprintf( stderr, "Insufficient storage. Exiting...\n\n" );
    exit( EXIT_SUCCESS );
  }

  store( filename, m1, m2, n ); /* read data into m1 and m2 */
  mult( m1, m2, m3, n );        /* m3 = m1 * m2 */
  print( m3, n );               /* print m3 */

  /* free storage for m1, m2, and m3 */
  freeMatrix( m1, n );
  freeMatrix( m2, n );
  freeMatrix( m3, n );
  
  return EXIT_SUCCESS;
}  

/* Create a matrix of side n, i.e., a matrix
 * that contains n x n int cells.
 */
Matrix createMatrix( int n )
{
  Matrix m;
  int i;

  m = ( Matrix ) malloc( n * sizeof ( int* ) );
  if ( NULL == m ) 
    return NULL;

  for ( i = 0; i < n; i++ ) {
    m[ i ] = ( int* ) malloc( n * sizeof ( int ) );
    if ( NULL == m[ i ] ) {
      freeMatrix( m, i );   /* avoid garbage */
      return NULL;
    }
  }
  return m;
}

/* Free all storage associated with matrix m. */
void freeMatrix( Matrix m, int n )
{
  int i;
  for ( i = 0; i < n; i++ )
    free( m[ i ] );
  free( m );
}

/* Multiply matrix m1 by matrix m2, storing the
 * product in matrix m3, where all three matrices are
 * n by n in size:
 *                  n-1
 *   m3[ i ][ j ] = SUM m1[ i ][ k ] * m2[ k ][ j ] 
 *                  k=0
 * and 0 <= i,j < n.
 */
void mult( Matrix m1, Matrix m2, Matrix m3, int n )
{
  int i, j, k;

  for ( i = 0; i < n; i++ ) 
    for ( j = 0; j < n; j++ ) {
      m3[ i ][ j ] = 0;
      for ( k = 0; k < n; k++ ) 
        m3[ i ][ j ] += m1[ i ][ k ] * m2[ k ][ j ];
    }
}

/* Store data in two source matrices. (We assume that
 * the file contains two integers per row, e.g.:
 *     3  5
 *     8 13
 *     ...
 * where the first integer is an element in m1 and the
 * second is an element in m2. The data are laid out 
 * left to right by rows.)
 */
void store( char* file, Matrix m1, Matrix m2, int n )
{
  FILE* fptr;
  int i, j;

  if ( ( fptr = fopen( file, "rb" ) ) == NULL ) {
    fprintf( stderr, "Can't open %s so exiting...\n\n", file );
    exit( EXIT_SUCCESS );
  }

  for ( i = 0; i < n; i++ ) 
    for ( j = 0; j < n; j++ ) 
      fscanf( fptr, "%d %d", &m1[ i ][ j ], &m2[ i ][ j ] );

  fclose( fptr );
}

void print( Matrix m, int n )
{
  int i, j;

  for ( i = 0; i < n; i++ ) {
    putchar( '\n' );
    for ( j = 0; j < n; j++ )
      printf( "%d ", m[ i ][ j ] );
  }
}


