murphys@cod.UUCP (Steven P. Murphy) (06/23/87)
The following example is what I would like to be able to do. Is it possible ? I tried something like this twice but it didn't work either time, though it be from my inexperience with C. #define ROWS1 500 #define COLUMNS1 30 #define ROWS2 400 #define COLUMNS2 20 main() { static double data1[ROWS][COLUMNS]; static double data2[ROWS][COLUMNS]; int n, m; n1 = 300; m1 = 15; n2 = 200; m2 = 18; . . . matrix_stuff(n1, m1, data1, ROWS1, COLUMNS1); . . . matrix_stuff(n2, m2, data2, ROWS2, COLUMNS2); . . . } /* end of main */ matrix_stuff(a, b, array, x, y); int a, b, x, y; double array[x][y]; { int i, j; . . . for(i = 0;i <= a;i++) /* step through the rows */ for(j = 0;j <= b;j++) /* step through the columns */ { operate on the part of the matrix "array" that was used in main } . . . } /* end of matrix_stuff */
edw@ius2.cs.cmu.edu (Eddie Wyatt) (06/23/87)
In article <733@cod.UUCP>, murphys@cod.UUCP (Steven P. Murphy) writes: > > > The following example is what I would like to be able to do. Is it possible ? > > I tried something like this twice but it didn't work either time, though > it be from my inexperience with C. > > > > #define ROWS1 500 > #define COLUMNS1 30 > > #define ROWS2 400 > #define COLUMNS2 20 > > main() > { > static double data1[ROWS][COLUMNS]; > static double data2[ROWS][COLUMNS]; > > int n, m; > > n1 = 300; > m1 = 15; > n2 = 200; > m2 = 18; > . > . > . > matrix_stuff(n1, m1, data1, ROWS1, COLUMNS1); > . > . > . > matrix_stuff(n2, m2, data2, ROWS2, COLUMNS2); > . > . > . > } /* end of main */ > > > > matrix_stuff(a, b, array, x, y); > > int a, b, x, y; > double array[x][y]; > > { > int i, j; > . > . > . > for(i = 0;i <= a;i++) /* step through the rows */ > for(j = 0;j <= b;j++) /* step through the columns */ > { > operate on the part of the > matrix "array" that was used in main > } > . > . > . > } /* end of matrix_stuff */ In the direct way, unfortunately no. I can see no reason why C doesn't support a construct like that, Fortrash does. And it wouldn't make the code generated much less efficient - the index function could have the dimensions plugged in when the matrix function is called. Note, I said not much less efficient - there may be some optimizations that the compiler may realize about the array indexes that it can't with "dynamic" bounds. One posible solution is to treat the matrix as an array of doubles and write you own indexing function. Example : matrix_stuff(a,b,array,x,y) int a,b,x,y; double array[]; { register int i,j; ..... for (i = 0; i <= a; i++) for (j = 0; j <= b; j++) { submatrix[i][j] = array[i*y+j]; /* indexing function ^ */ ...... } } In general, the indexing function in C for type a[N1][N2]...[Nn]; a[I1][I2]...[In] is *( sizeof(type)*(In + Nn*(I{n-1} +N{n-1}*(I{n-2} + N{n-2}.... N3*(I2 + N2*I1))))...) By declaring the array "array" to be an array of doubles you in a sence fill in the sizeof value and supply the pointer operation. This indexing function is use because arrays are in is that column or row major form? - I keep forgetting which is which. -- Eddie Wyatt e-mail: edw@ius2.cs.cmu.edu terrorist, cryptography, DES, drugs, cipher, secret, decode, NSA, CIA, NRO.
gwyn@brl-smoke.ARPA (Doug Gwyn ) (06/23/87)
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]; >{ Sorry, that is not legal in C, although the analogous operation is commonly encountered in Fortran programming. In C, formal array parameters must be declared with constant dimensions*, although the leftmost dimension is unimportant (so that [1] or [] will do for it). Keep in mind that an attempt to pass the name of an array as an actual parameter in a function call results in a pointer to the first element of the array as the real parameter. Also remember that all arrays are really 1-dimensional aggregates of objects, which in turn may be arrays. This subject should be covered in any good C programming text, although probably someone like Torek will post examples. The point I wish to make is that you can get into trouble if you try to take an "intuitive" approach to using arrays in C; you need to carefully examine just what the rules are. Once you do that, you'll find several alternate ways to accomplish what you're trying to do. *I once suggested to Dennis Ritchie that this restriction on formal array parameters could be removed, and although he seemed to agree that there was no theoretical problem doing so, we agreed that it would add complexity to compilers. He seemed to think that the feature would be of insufficient general utility to offset the added complexity. (I hope I haven't misrepresented his position; it was a long time ago.)
nate@altos86.UUCP (Nathaniel Ingersoll) (06/24/87)
In article <733@cod.UUCP> murphys@cod.UUCP (Steven P. Murphy) writes: ...declarations... >static double data1[ROWS][COLUMNS]; >static double data2[ROWS][COLUMNS]; make that static double data1[ROWS1][COLUMNS1]; static double data2[ROWS2][COLUMNS2]; > >int n, m; > >n1 = 300; >m1 = 15; > . >matrix_stuff(n1, m1, data1, ROWS1, COLUMNS1); > . >matrix_stuff(n2, m2, data2, ROWS2, COLUMNS2); >} > >matrix_stuff(a, b, array, x, y); >int a, b, x, y; >double array[x][y]; >{ >int i, j; > . >for(i = 0;i <= a;i++) /* step through the rows */ > for(j = 0;j <= b;j++) /* step through the columns */ The problem here is with the double array[x][y]; declaration. You need to declare all the sizes of an arrays dimensions except the first; and this declaration must be _constant_. To do what you want you would probably have to do something like /* * note that the x array bound is unneeded * * various purists will probably be offended by the * following declaration for "array" */ matrix_stuff(a, b, array, x, y) int a, b, x, y; double *array; { #define place(u, v) ((u)*y + (v)) int i, j; /* following with your example, though you'd probably want to eliminate the a and b parameters and use x and y instead */ for (i = 0;i < a;i++) for (j = 0;j < b;j++) /* ...use array[place(i, j)] in here.... for example, this would mutiply all elements of array by 2: array[place(i, j)] *= 2; */ }
franka@mmintl.UUCP (Frank Adams) (06/26/87)
In article <733@cod.UUCP> murphys@cod.UUCP (Steven P. Murphy) writes: >The following example is what I would like to be able to do. Is it possible ? >... >matrix_stuff(a, b, array, x, y); > >int a, b, x, y; >double array[x][y]; No. Array bounds in C have to be constants. To do this, you would have to do the array arithmetic explicitly. Sorry. -- Frank Adams ihnp4!philabs!pwa-b!mmintl!franka Ashton-Tate 52 Oakland Ave North E. Hartford, CT 06108
chris@mimsy.UUCP (Chris Torek) (06/27/87)
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 * <variable> + 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
beede@hubcap.UUCP (Mike Beede) (06/30/87)
in article <2215@mmintl.UUCP>, franka@mmintl.UUCP (Frank Adams) says: ] ] In article <733@cod.UUCP> murphys@cod.UUCP (Steven P. Murphy) writes: ]>The following example is what I would like to be able to do. Is it possible ? ]>... ]>matrix_stuff(a, b, array, x, y); ]> ]>int a, b, x, y; ]>double array[x][y]; ] ] No. Array bounds in C have to be constants. To do this, you would have to ] do the array arithmetic explicitly. Sorry. However, you CAN do the arithmetic explicitly if you like, using macros to maintain fair readability: something like #define matrix_el(array,i,j) (array[y*sizeof(double)+j]) which produces an l-valued expression. At the same time, you can insert temporary bounds-checking until you're sure your code is correct (or forever, whichever is smaller :-) ). Now, of course, your declaration for array is double array[]; and you can have things like matrix_el(A,i,j) = matrix_el(A,i+1,j) , etc. Of course, since this depends on the value of y, it is still sloppy, but you can include y as a discriptor bolted onto the array or something similar, if you like (which the macro would reference). -- Mike Beede UUCP: . . . !gatech!hubcap!beede Computer Science Dept. ARPA: BEEDE@TECNET-CLEMSON.ARPA Clemson University INET: beede@hubcap.clemson.edu Clemson SC 29631-1906 PH: (803)656-{2845,3444}
beede@hubcap.UUCP (Mike Beede) (07/01/87)
in article <238@hubcap.UUCP>, beede@hubcap.UUCP (Me) says: > > #define matrix_el(array,i,j) (array[y*sizeof(double)+j]) > which of course is completely bogus. I'm not sure _where_ that sizeof(double) popped in, but anyway the correct version is #define matrix_el(array,i,j) (array[i*y+j]) , as a kind reader pointed out by email--thanks. I guess I'll see a few cards and letters on this one. P.S., Well, not _completely_ bogus -- it _does_ produce an l-valued expression :-) -- Mike Beede UUCP: . . . !gatech!hubcap!beede Computer Science Dept. ARPA: BEEDE@TECNET-CLEMSON.ARPA Clemson University INET: beede@hubcap.clemson.edu Clemson SC 29631-1906 PH: (803)656-{2845,3444}
kurt@hi.UUCP (Kurt Zeilenga) (07/02/87)
He writes: >in article <238@hubcap.UUCP>, beede@hubcap.UUCP (Me) says: >> >> #define matrix_el(array,i,j) (array[y*sizeof(double)+j]) >> >which of course is completely bogus. I'm not sure _where_ that >sizeof(double) popped in, but anyway the correct version is > >#define matrix_el(array,i,j) (array[i*y+j]) , > Actually, (I'm being picky) a better version is: #define matrix_el(array,i,j) array[(i)*y+(j)] You should always use '(' and ')' to surround arguments in macros (and the macro itself if needed) to insure the evaulation order of any expression in the expanding macro. Mike's macro, if used like matrix(array,i+1,j), would return something a bit different then advertised. -- Kurt Zeilenga (zeilenga@hc.dspo.gov) I want my talk.flame! "So long, Mom, I'm off to kill a commie..."
beede@hubcap.UUCP (Mike Beede) (07/03/87)
in article <245@hubcap.UUCP], beede@hubcap.UUCP (ME AGAIN) says:
] in article <238@hubcap.UUCP>, beede@hubcap.UUCP (Me) says:
]> #define matrix_el(array,i,j) (array[y*sizeof(double)+j])
]>
] which of course is completely bogus. I'm not sure _where_ that
] sizeof(double) popped in, but anyway the correct version is
]
] #define matrix_el(array,i,j) (array[i*y+j]) ,
]
Well--now the macro is correct if you don't use anything but single constants
or variables as the indexing arguments. If we do something like
matrix_el(A,k+5,m)
it expands to
(A[k+5*y+m])
which is surely bogus, since this is k+(5*y)+m instead of (k+5)*y+m.
The moral of the story, as Mark Brader was kind enough to point out
(twice!), is to always parenthesize the arguments of a macro when they
occur in the rhs, like the (REALLY) correct version:
#define matrix_el(array,i,j) (array[(i)*y+(j)]) ,
The sad part is, not only did Mark include the correct version in his
mail to me (which I discarded), but I myself was once burned by the
lack of parenthesis in a macro.
Sorry this took so long to iron out.
--
Mike Beede UUCP: . . . !gatech!hubcap!beede
Computer Science Dept. ARPA: BEEDE@TECNET-CLEMSON.ARPA
Clemson University INET: beede@hubcap.clemson.edu
Clemson SC 29631-1906 PH: (803)656-{2845,3444}
walters@osubem.UUCP (walters) (07/05/87)
What follows is some sample code that demonstrates using an 'array of pointer to an array of double'. This is a nice portable way to get variable dimension arrays (I learned FORTRAsh before I learned C). It's great for swapping rows when doing matrix algebra and it also aviods doing array indexing explicitly. Obviously it could be used with other types (ie. integer). Hope someone finds this useful. #include <stdio.h> #include <math.h> typedef double *RWP; typedef struct { RWP rw; } A; void do_something(a, r, c) A a[]; int r, c; { int i, j; RWP ai; for (i = 0; i < r; i++) { ai = a[i].rw; for (j = 0; j < c; j++) ai[j] = -ai[j]; } return; } void do_something_else_another_way(a, r, c) A a[]; int r, c; { int i, j; for (i = 0; i < r; i++) for (j = 0; j < c; j++) a[i].rw[j] = fabs(a[i].rw[j]); return; } int arr_alloc(a, r, c) /* allocate the array */ A **a; int r, c; { register int i, j; if ((*a = (A *) malloc(r * sizeof(A))) == (A *) NULL) return(0); for (i = 0; i < r; i++) { (*a)[i].rw = (RWP) malloc(c * sizeof(double)); if ((*a)[i].rw == (RWP) NULL) return(0); } for (i = 0; i < r; i++) for (j = 0; j < c; j++) (*a)[i].rw[j] = 0.0; return(1); } void arr_free(a, r) /* free the array */ A **a; int r; { register int i; for (i = 0; i < r; i++) free((*a)[i].rw); free(*a); return; } #define MSIZE 10 main() { static A *a; if (!arr_alloc(&a, MSIZE, MSIZE)) abort(); do_something(a, MSIZE, MSIZE); do_something_else_another_way(a, MSIZE, MSIZE); arr_free(&a, MSIZE); } ----- Harold G. Walters Internet: walters@ce.okstate.edu School of Civil Engineering Uucp: {cbosgd, ihnp4, rutgers, seismo, Oklahoma State University uiucdcs}!okstate!osubem!walters Stillwater, OK 74078
beede@hubcap.UUCP (Mike Beede) (07/05/87)
in article <254@hubcap.UUCP>, beede@hubcap.UUCP (Mike Beede) says: > > #define matrix_el(array,i,j) (array[(i)*y+(j)]) , Well, Mark Brader strikes again, pointing out that the value of ``array'' could well be an expression, too. I have to agree, so the final version of this blasted thing is #define matrix_el(array,i,j) ((array)[(i)*y+(j)]) (array being an expression is not too unlikely, given C programmers' penchant for passing addresses like buffer+offset . If you're doing your own matrix sizing, you might be allocating said matrices out of a big double array . . . -- Mike Beede UUCP: . . . !gatech!hubcap!beede Computer Science Dept. ARPA: BEEDE@TECNET-CLEMSON.ARPA Clemson University INET: beede@hubcap.clemson.edu Clemson SC 29631-1906 PH: (803)656-{2845,3444}