Dan Karron@UCBVAX.BERKELEY.EDU (04/09/91)
Here is a problem at the border of the C-language. It is on the edge of c's value as a terse, compact language, and a slippery mess when it comes to arrays and pointers. I would like someone to show me that this is really a beautiful feature to be appreciated and loved! Here is my problem. I have allocated a tree of structures, and I want to pass a pointer to a piece of a structure to a subroutine. Now what I want to pass is a Pointer to an 2 dim CONTIGUOUS array of floats (Like a Matrix typedef, in that each float is in storage adjacent to each other, not an array of pointers to a list of floats) In the receiving subroutine, I would like to be able to reference each element in the array pointed to by the same indexes as in the main structure. Here are the decls and deffs: typedef struct LineTag { float l[2][3],V[2][3]; int DrawMe,Inny,Outie; } Line; typedef struct CompositeTag { struct LineTag *HotLinePointer; struct LineTag SkeweringLines[HOT_SPOTS][HOT_LINES]; struct LineTag LineTween[HOT_SPOTS][HOT_LINES]; Matrix CompositeMatrix; int NumberCompositeStacks,HotStack, HotSlice,HotCardinal,HotLine; char CompositeName[80]; } Composite; Now I want to call a subroutine that works on the vertices of the line as an array of two sets of three plane normal coeff. Hence the decl of the Line as a 2 by 3 array. If I want to operate on the substituent planes, they I want to pass a pointer to the individual plane. If I want to work on the line, I want to pass a pointer to a pair of planes. I want to pass a LIST of lines, or a LIST of planes, where there can be an arbitrary number of elements. I can do this by blinding the compiler with void * and &p->LineInstance.V[0][0] but I would like the debugger and the comiler to know the array bounds for what is pointed by. So, How do I get this meta-code to fly? I gets lots of compiler complaints, Here is what it says: ---------------------------------------------------------------------------- void NitherNoid(int mm,float llist[][2][3],float point[3]); void KnitItTight() { register int i,j,l; static int svd_line_count; float *svd_line_list[2][3]; /* a list of pointers to lines */ svd_line_coune=0; svd_line_list=(void *)0; for(i=0;i<HOT_LINES;i++) { if(!ArenaDirectory->Composite->SkeweringLines[l][i].DrawMe) continue; svd_line_count++; if(svd_line_list) /* allocate list space as we need it */ { svd_line_list=realloc(svd_line_list,svd_line_count*sizeof(float *)); } else { svd_line_list=calloc(svd_line_count,sizeof(float *)); } svd_line_list[svd_line_count-1]= &ArenaDirectory->Composite->SkeweringLines[l][i].V; /* attach a pointer to our line */ } if(svd_line_count > 1) { NitherNoid(svd_line_count,svd_line_list,ArenaDirectory->Composite->CardinalMark[l].v); ArenaDirectory->Composite->CardinalMark[l].DrawMe=TRUE; printf("%s:%f,%f,%f\n",ArenaDirectory->Composite->CardinalMark[l].MarkName, ArenaDirectory->Composite->CardinalMark[l].v[0], ArenaDirectory->Composite->CardinalMark[l].v[1], ArenaDirectory->Composite->CardinalMark[l].v[2]); } free(svd_line_list); } /******************************************************************************/ The compiler won't let me attach a pointer to the array of line params. karron:~/D.Image/D.Arenas/D.PixelPicker:159make .c.o RULE PixelPicker.o : triggered by PixelPicker.c cc -DDEBUG -DDANS_HACK -DIRIS_NEWS -I/usr/people/karron/D.Include -g 2 -prototypes -float -c PixelPicker.c ccom: Error: PixelPicker.c, line 140: illegal lhs of assignment operator svd_line_list=(void *)0; -----------------------^ ccom: Error: PixelPicker.c, line 149: illegal lhs of assignment operator svd_line_list=realloc(svd_line_list,svd_line_count*sizeof(fl oat *)); ---------------------------------------------------------------------- -------^ ccom: Error: PixelPicker.c, line 153: illegal lhs of assignment operator svd_line_list=calloc(svd_line_count,sizeof(float *)); --------------------------------------------------------------^ ccom: Warning: PixelPicker.c, line 155: & before array or function: ignored svd_line_list[svd_line_count-1]= &ArenaDirectory->Composite->Skeweri ngLines[l][i].V; ---------------------------------------------------------------------- ---------------^ ccom: Error: PixelPicker.c, line 155: illegal lhs of assignment operator svd_line_list[svd_line_count-1]= &ArenaDirectory->Composite->Skeweri ngLines[l][i].V; ---------------------------------------------------------------------- ---------------^ ccom: Error: PixelPicker.c, line 161: bounds of array argument and prototype disagree: 3 vs 2 NitherNoid(svd_line_count,svd_line_list,ArenaDirectory->Composite->C ardinalMark[l].v); ---------------------------------------------------------------------- ----------------^ How do I make a list of pointers to a 2 dim array that works ? Cheers! dan. | karron@nyu.edu (e-mail alias ) Dan Karron, Research Associate | | Phone: 212 263 5210 Fax: 212 263 7190 New York University Medical Center | | 560 First Avenue Digital Pager <1> (212) 397 9330 | | New York, New York 10016 <2> 10896 <3> <your-number-here> |
jit@SLIC.CELLBIO.DUKE.EDU (Jit Keong Tan) (04/09/91)
In article <9104082133.AA15472@karron.med.nyu.edu> >>void NitherNoid(int mm,float llist[][2][3],float point[3]); This is no difference than void NitherNoid(int mm,float llist[][][],float point[]); or void NitherNoid(int mm, float ***llist, float *point); the compiler will ignore the dimension that you declare in function prototyping. ---- >> float *svd_line_list[2][3]; /* a list of pointers to lines */ >> svd_line_list=(void *)0; (I suppose you mean float * instead of void * cast) There is a misconception of array and pointers here. you first declare svd_line_list as an array, then you treat it as a pointer, this is wrong. Because you did not tell the compiler where you want to store the value (float *)0 Let's do it step by step, (and I hope this is what you want) 1) svd_line_list[0][0] = (float *)0; /* assign 1st element to be NULL */ 2) *svd_line_list[0] = (float *)0; /* same thing */ /* same difference, just look more impressive :-) */ 3) **svd_line_list = (float *)0; For all other similar problems, if you do the translation step by step in terms of array before converting them into pointers, lots of problem can be avoided. I didn't try to read carefully want you want but I guess you are trying to pass the dimension of array into a function. How about include its dimension in the structure such as typedef struct CompositeTag { int hot_spots = HOT_SPOTS; /* <==== These two are added */ int hot_lines = HOT_LINES; /* <==== These two are added */ struct LineTag *HotLinePointer; struct LineTag SkeweringLines[HOT_SPOTS][HOT_LINES]; struct LineTag LineTween[HOT_SPOTS][HOT_LINES]; Matrix CompositeMatrix; int NumberCompositeStacks,HotStack, HotSlice,HotCardinal,HotLine; char CompositeName[80]; } Composite; Because C doesn't care about array bound at all. Hope this help. -------------------------------------------------------- Jit Keong Tan | internet: jit@slic.cellbio.duke.edu (919) 684-8098 | bitnet : tan00001@dukemc.bitnet -------------------------------------------------------- U.S. Mail: Duke University Medical Center Department Of Cell Biology Box 3709 Nanaline Duke Bldg, Rm. 349 Durham, NC 27710
jit@SLIC.CELLBIO.DUKE.EDU (Jit Keong Tan) (04/09/91)
In message <9104082133.AA15472@karron.med.nyu.edu> >>I want to pass a LIST of lines, or a LIST of planes, where there can be an >>arbitrary number of elements. I can do this by blinding the compiler with >>void * and &p->LineInstance.V[0][0] but I would like the debugger and the >>comiler to know the array bounds for what is pointed by. It just occurred to me that I may not reply to some of your message, which is probably what you want to know. I usually deference the whole array to a simple one dimension. Then knowing that C array is a column-major array, I can just calculate the position in the array like a matrix. You may not like the way I do it but this will give you a more comfortable feeling about array and pointer. example, ---------- #include <stdio.h> #define COL 3 #define ROW 4 main() { int inttype[COL][ROW]; int *odptr; /* one dim. pointer */ int index, in2; odptr = inttype[0]; for (index = 0; index < COL; index ++) for (in2 = 0; in2 < ROW; in2 ++) inttype[index][in2] = in2 + ROW*index; /* If you reverse the order of ROW and COL, for large arrays, this could create a lot of page faults. for (in2 = 0; in2 < ROW; in2 ++) for (index = 0; index < COL; index ++) inttype[index][in2] = in2 + ROW*index; */ /* it is important to declare odptr correctly so that the compiler will know how many bytes to advance In other words, array inttype[2][3] would be : */ *(odptr + 2*ROW + 3) = 7777; for (index = 0; index < COL; index ++) for (in2 = 0; in2 < ROW; in2 ++) printf("col= %d, row=%d, value=%d\n", index, in2, inttype[index][in2]); for (index = 0; index < ROW*COL; index ++) printf("index = %d, content=%d\n",index, *odptr++); /* watch out. odptr points beyond the last element here. */ }
tarolli@westcoast.esd.sgi.com (Gary Tarolli) (04/09/91)
In article <9104082133.AA15472@karron.med.nyu.edu>, Dan Karron@UCBVAX.BERKELEY.EDU writes: > > Here is a problem at the border of the C-language. It is on the edge of > c's value as a terse, compact language, and a slippery mess when it comes to > arrays and pointers. I would like someone to show me that this is really > a beautiful feature to be appreciated and loved! > > Here is my problem. I have allocated a tree of structures, and I want to > pass a pointer to a piece of a structure to a subroutine. Now what I want to > pass is a Pointer to an 2 dim CONTIGUOUS array of floats (Like a Matrix typedef, > in that each float is in storage adjacent to each other, not an array of pointers to a list of floats) > > In the receiving subroutine, I would like to be able to reference each > element in the array pointed to by the same indexes as in the main structure. > I am not sure that this is what you need, but here goes. If you have an array of float, eg. mat[4][4] and you pass it to a subroutine, you can declare the incoming parameter as float (*inmat)[4]; /* inmat is a pointer to 4 floats */ You can then index the array as inmat[row][column]; With different declarations (or castings) you can treat the array as having different dimensions, eg. float (*inmat5)[5]; inmat5 = ((*)[5])inmat; inmat5[1][4]; You can also assign these pointers and increment them: float mat[4][4]; inmat = mat[2]; /* assign it to point to third row */ inmat++; /* increment it to fourth row */ Although you can do most of this with a paramenter declaration, eg. inmat[][4], you cannot declare extra parameters. Thus this technique of using a pointer to a single dimen. array of floats is much more versatile. WARNING - although I have done this and I know it works, I have not checked my examples above with the compiler. So they may be off by a paren or two. -------------------- Gary Tarolli