/* Shaun Guth CIS15BG, Lee-Klawender November 8, 2006 Mac OSX 10.4.8 gcc 4.0.1 (build 5363) Lab 5 (Matrices/Structs) This program tests some two-dimensional array functions */ #include #include #include #define MAX_DIMENSION 8 #define MIN_DIMENSION 2 #define MAX_DOUBLE 100.0 // define our 2-dimensional array struct typedef struct { double** data; int rows; int cols; } MATRIX; // testing framework void get_dimensions (int* x, int* y); MATRIX* init_matrix (MATRIX* m, int x, int y); void free_matrix (MATRIX* m); MATRIX* fill_matrix (MATRIX* m); // matrix operations void add_matrices (MATRIX* m1, MATRIX* m2, MATRIX* r); void invert_matrix (MATRIX* m); void multiply_matrices (MATRIX* m1, MATRIX* m2, MATRIX* r); // output void print_matrix (char* label, MATRIX* m); /*-------------------------------------------------------------------------*/ // program entry point int main (void) { MATRIX matrix1, matrix2, matrix3; // matrices int dx,dy; // actual dimensions generated // seed random number generator //srand(3); srand( (unsigned)time(NULL) ); // set the initial dimensions for this run get_dimensions(&dx, &dy); // initialize the first matrix if (NULL == init_matrix(&matrix1, dx, dy)) { printf("Error allocating memory for matrix1, exiting!\n"); return 1; } // fill the first matrix with random numbers fill_matrix(&matrix1); // initialize the second matrix if (NULL == init_matrix(&matrix2, dx, dy)) { printf("Error allocating memory for matrix2, exiting!\n"); } // fill the second matrix with random numbers fill_matrix(&matrix2); // print initial values to screen print_matrix("First Matrix:", &matrix1); print_matrix("Second Matrix:", &matrix2); // add the first two matrices together, storing the sum in matrix3 add_matrices(&matrix1, &matrix2, &matrix3); // print result print_matrix("Sum Matrix:", &matrix3); // invert the second matrix invert_matrix(&matrix2); // when printing, remember that the dimensions are now inverted print_matrix("Inverted Matrix:", &matrix2); /* // multiply the first two matrices, storing product in third matrix multiply_matrices(&matrix1, &matrix2, &matrix3); // print the result of a multiplication print_matrix("Product Matrix:", &matrix3); */ // successfully completed program return 0; } /*-------------------------------------------------------------------------*/ MATRIX* init_matrix (MATRIX* m, int x, int y) { /* PURPOSE: Allocate memory for MATRIX m ACCEPTS: m (MATRIX pointer) x (int) num of rows y (int) num of cols RETURNS: NULL on error, m otherwise REMARKS: */ int i; // loop index // invalid dimensions if (0 >= x || 0 >= y) { return NULL; } free_matrix(m); // allocate new array pointers m->data = (double**)calloc(x, sizeof(double*)); if (NULL == m->data) { return NULL; } // allocate data storage for (i = 0; i < x; i++) { m->data[i] = (double*)calloc(y, sizeof(double)); if (NULL == m->data[i]) { return NULL; } } // assign dimensions m->rows = x; m->cols = y; // allocated successfully return m; } /*-------------------------------------------------------------------------*/ void free_matrix (MATRIX* m) { /* PURPOSE: Frees memory for an allocated MATRIX m ACCEPTS: m (MATRIX pointer) RETURNS: (none) REMARKS: Checks to see if there's anything to free first */ int i; // loop index printf("Inside free_matrix()\n"); if (NULL != m->data && 0 < m->rows && 0 < m->cols) { printf("m->data is NOT NULL, rows and cols are > 0\n"); for (i = 0; i < m->rows; i++) { if (NULL != m->data[i]) { printf(" freeing row %d\n", i); free(m->data[i]); } } printf("freeing m->data\n"); free(m->data); } m->data = NULL; } /*-------------------------------------------------------------------------*/ void get_dimensions (int* x, int* y) { /* PURPOSE: Get 2 random values from the set [MAX_DIMENSION,MIN_DIMENSION] ACCEPTS: x, y (int pointers) to store values in RETURNS: (none) REMARKS: Random number generator should be seeded with a call to srand() */ *x = rand() % (MAX_DIMENSION-MIN_DIMENSION+1) + MIN_DIMENSION; *y = rand() % (MAX_DIMENSION-MIN_DIMENSION+1) + MIN_DIMENSION; return; } /*-------------------------------------------------------------------------*/ MATRIX* fill_matrix (MATRIX* m) { /* PURPOSE: Initialize a matrix of doubles with random values ACCEPTS: m - MATRIX pointer RETURNS: m REMARKS: (none) */ int ix,iy; // loop indices for (ix = 0; ix < m->rows; ix++) { for (iy = 0; iy < m->cols; iy++) { m->data[ix][iy] = (double)rand() / RAND_MAX * (MAX_DOUBLE+1); } } return m; } /*-------------------------------------------------------------------------*/ void add_matrices (MATRIX* m1, MATRIX* m2, MATRIX* r) { /* PURPOSE: Add two matrices together ACCEPTS: m1, m2, r - MATRIX pointers RETURNS: (none) REMARKS: The 'r' parameter stores the sum of m1 + m2 */ int ix,iy; // loop indices // free the old result matrix free_matrix(r); // check that m1 and m2 are the same size if (m1->rows != m2->rows || m1->cols != m2->cols) { return; } // initialize new result matrix if (NULL == init_matrix(r, m1->rows, m1->cols)) { return; } // add matrices for (ix = 0; ix < m1->rows; ix++) { for (iy = 0; iy < m1->cols; iy++) { r->data[ix][iy] = m1->data[ix][iy] + m2->data[ix][iy]; } } return; } /*-------------------------------------------------------------------------*/ void invert_matrix (MATRIX* m) { /* PURPOSE: Inverts the given matrix ACCEPTS: m - MATRIX to be inverted RETURNS: (none) REMARKS: After inversion, m->rows and m->cols are swapped */ int ix, iy; // loop indices MATRIX tmp; if (NULL == init_matrix(&tmp, m->cols, m->rows)) { return; } for (ix = 0; ix < m->rows; ix++) { for (iy = 0; iy < m->cols; iy++) { tmp.data[iy][ix] = m->data[ix][iy]; } } free_matrix(m); m->rows = tmp.rows; m->cols = tmp.cols; m->data = tmp.data; return; } /*-------------------------------------------------------------------------*/ void multiply_matrices (MATRIX* m1, MATRIX* m2, MATRIX* r) { /* PURPOSE: Multiplies two matrices together ACCEPTS: m1, m2, r - MATRIX pointers RETURNS: (none) REMARKS: m2 should be inversely sized from m1 ie, if m1 is 2x3, m2 should be 3x2 */ int i, j, k; // loop indices // free the old result matrix free_matrix(r); // check that m1 and m2 are inversely sized if (m1->cols != m2->rows || m1->rows != m2->cols) { return; } // initialize new result matrix (will be square) if (NULL == init_matrix(r, m1->rows, m1->rows)) { return; } // multiply for (i = 0; i < m1->rows; i++ ) { for (j = 0; j < m1->rows; j++) { r->data[i][j] = 0.0; // initialize result for (k = 0; k < m1->cols; k++) { r->data[i][j] += m1->data[i][k] * m2->data[k][j]; } } } return; } /*-------------------------------------------------------------------------*/ void print_matrix (char* label, MATRIX* m) { /* PURPOSE: Prints a matrix to the screen ACCEPTS: label - string to print out before the matrix m - MATRIX pointer RETURNS: (none) */ int ix,iy; // loop indices printf( "%s\n", label ); if (NULL == m->data) { printf("Error with matrix.\n"); return; } for (ix = 0; ix < m->rows; ix++) { for (iy = 0; iy < m->cols; iy++) { printf( "% 8.2f ", m->data[ix][iy] ); } printf( "\n" ); } printf( "\n" ); return; } /*-------------------------------------------------------------------------*/