Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!mimsy!chris From: chris@mimsy.UUCP (Chris Torek) Newsgroups: comp.lang.c Subject: Re: Two dimensional arrays in C Message-ID: <7222@mimsy.UUCP> Date: Fri, 26-Jun-87 22:12:46 EDT Article-I.D.: mimsy.7222 Posted: Fri Jun 26 22:12:46 1987 Date-Received: Sat, 27-Jun-87 12:33:27 EDT References: <733@cod.UUCP> Organization: U of Maryland, Dept. of Computer Science, Coll. Pk., MD 20742 Lines: 154 In article <733@cod.UUCP> murphys@cod.UUCP (Steven P. Murphy) writes: >matrix_stuff(a, b, array, x, y); >int a, b, x, y; >double array[x][y]; >{ [does not work.] C does not allow variables as dimension, not even in parameter declarations. Given that the caller wants to pass two differently- shaped matrices (one [500][30], one [400][20]), the only way to do this without creating a vector of vectors is to have the caller pass the address of mat[0][0]: #define M1A ... /* and likewise for 1B, 2A, 2B */ main(...) { static double m1[M1A][M1B]; static double m2[M2A][M2B]; ... matrix_stuff(a, b, &m1[0][0], M1B);/* M1A is irrelevant */ matrix_stuff(c, d, &m2[0][0], M2B);/* likewise */ ... } matrix_stuff(a, b, array, y) int a, b, y; double *array; { int i, j; for (i = 0; i < a; i++) { for (j = 0; j < b; j++) { v = array[i * y + j]; ... array[i * y + j] = v; } } } If the `shape' of the two matrices is the same---that is, all dimensions save the first are the same---you can do this: main(...) { static double m1[R1][C], m2[R2][C]; ... matrix_stuff(a, b, m1); matrix_stuff(c, d, m2); ... } matrix_stuff(a, b, array) int a, b; double (*array)[C]; { int i, j; for (i = 0; i < a; i++) for (j = 0; j < b; j++) /* work on array[i][j] here */; } This generates approximately the same code, except that instead of having `array[i * + j]', the compiler can generate `array[i * C + j]'. In either case a good optimiser will pull the `i * expr' expression out of the `for j' loop, but the chance that your compiler has a good optimiser is rather slim. The method I prefer is vectors of vectors: struct matrix { double **m_data; /* vectors of (double *) */ int m_rows; /* number of rows */ int m_cols; /* and columns */ }; struct matrix *make_matrix(); main() { struct matrix *m1, *m2; ... m1 = make_matrix(rows, cols); m1->m_data[i][j] = value; m2 = make_matrix(rows2, cols2); ... matrix_stuff(m1); matrix_stuff(m2); ... } matrix_stuff(m) register struct matrix *m; { register int i, j; for (i = 0; i < m->m_rows; i++) for (j = 0; j < m->m_cols; j++) /* do things with m->m_data[i][j] */; } struct matrix * make_matrix(nr, nc) register int nr, nc; { register struct matrix *m; register double **p; #define alloc(v, n, t) \ if ((v = (t *) malloc(n * sizeof (t))) != NULL); \ else abort_because_out_of_memory() /* Allocate: */ alloc(m, 1, struct matrix); /* the matrix; */ alloc(p, nr, double *); /* the vector of vectors; */ m->m_rows = nr; m->m_cols = nc; m->m_data = p; while (--nr >= 0) /* and each vector */ alloc(*p++, nc, double);/* of doubles. */ #undef alloc return (m); } This is `neater' in that the size of the matrix is carried about with the matrix itself, and no multiplication is necessary to find any matrix element. The definition of alloc() is not suitable for a general matrix library, since it aborts the program if it cannot get enough memory, but this should suffice for illustration. Note that you can dynamically allocate `flat' matrices, too: struct flatmat { double *fm_data; int fm_rows, fm_cols; }; #define FM_ELT(fm, i, j) ((fm)->fm_data[(i) * (fm)->fm_cols + (j)]) ... struct flatmat * flatmat_alloc(nr, nc) { ... alloc(fm, 1, struct flatmat); alloc(fm->fm_data, nr * nc, double); fm->fm_rows = nr; fm->fm_cols = nc; return (fm); } but this requires all those multiplies (again, unless you have a good optimiser), and precludes such things as upper triangular matrices. More complex methods of remembering the size and shape of each matrix are appropriate in some situations. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690) Domain: chris@mimsy.umd.edu Path: seismo!mimsy!chris