[comp.sys.sgi] Calling real c-men...

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