Multidimensional array, passing to a function

M

Michael

Hello,

I've a couple of (automatically) created functions that take
2-dimensional array as inputs, like

void getMatrix( double M[2][2] )
{
M[0][0] = 1;
M[0][1] = 0;
M[1][0] = 0;
M[1][1] = 1;
}

The size of the matrices varies: 2x2, 3x2, etc. but is
always defined in the function header. I don't need all
matrices simultaneously. Is it allowed to pass an array that
has larger dimensions (i.e. those of the largest matrix)
than specified in the function header? Currently I tried this:
============================================================
#include <stdio.h>

void getMatrix( double M[2][2] );


void getMatrix( double M[2][2] )
{
M[0][0] = 1;
M[0][1] = 0;
M[1][0] = 0;
M[1][1] = 1;
};


int main( void )
{
double A[3][3];

void (*fnc)(double M[][]) = getMatrix;

(*fnc)( A );

printf("[ %.1f, %.1f]\n", A[0][0], A[0][1]);
printf("[ %.1f, %.1f]\n", A[0][2], A[1][0]);

return 0;
}
============================================================
Although the compiler takes it and the executable prints the
desired result, it seems a bit odd to me. The function
pointer seems to suppress the information of the array size.
Without this intermediate step the compiler throws an error
(which might be already a hint that the code is not valid).
The only other way a can think of is to create a bunch of
buffers and decide at each call which I have to use.

Regards

Michael
 
T

Tom St Denis

int main( void )
{
   double A[3][3];

   void (*fnc)(double M[][]) = getMatrix;

   (*fnc)( A );

   printf("[ %.1f, %.1f]\n", A[0][0], A[0][1]);
   printf("[ %.1f, %.1f]\n", A[0][2], A[1][0]);

   return 0;}

Probably the easier way to do this sort of anonymous thing is use a 1D
array then access it via macro

#define M(i, j) R[i*width+j]

Where "width" is a constant that the compiler can optimize [e.g. *4 ==
<<2 and so on, or more importantly just access the array with known
offsets if it unrolls your code or whatever].

The only other way I can think of doing this is with structs, e.g.

struct twobytwo { double M[2][2]; }

then you pass

void func(struct twobytwo *M);

Then you can have anonymous matrix functions that take (void *) and
they internally cast it to a pointer of the right struct. I can't
think of how you'd declare "a pointer to an array of 2 of array of 2
doubles" ...

Tom
 
K

Keith Thompson

Tom St Denis said:
Then you can have anonymous matrix functions that take (void *) and
they internally cast it to a pointer of the right struct. I can't
think of how you'd declare "a pointer to an array of 2 of array of 2
doubles" ...

% cdecl
Type `help' or `?' for help
cdecl> declare p as pointer to array 2 of array 2 of double
double (*p)[2][2]
cdecl>
%
 
M

Michael

Tom said:
int main( void )
{
double A[3][3];

void (*fnc)(double M[][]) = getMatrix;

(*fnc)( A );

printf("[ %.1f, %.1f]\n", A[0][0], A[0][1]);
printf("[ %.1f, %.1f]\n", A[0][2], A[1][0]);

return 0;}

Probably the easier way to do this sort of anonymous thing is use a 1D
array then access it via macro

#define M(i, j) R[i*width+j]

Where "width" is a constant that the compiler can optimize [e.g. *4 ==
<<2 and so on, or more importantly just access the array with known
offsets if it unrolls your code or whatever].

Thanks for your fast reply. If I got it right, you suggest
to avoid the use of a 2D array and stick to 1d one. Properly
I missed your point how to implement it, but does it
require a change in getMatrix?

I didn't mentioned it clearly in the first posting: the
"getMatrix" function is generated "somewhere else". Thus, I
have no control there. I could post process the function and
try to change the definitions, but i would prefer to leave
these functions untouched.

Thanks again for your help,

Michael
The only other way I can think of doing this is with structs, e.g.

struct twobytwo { double M[2][2]; }

then you pass

void func(struct twobytwo *M);

Then you can have anonymous matrix functions that take (void *) and
they internally cast it to a pointer of the right struct. I can't
think of how you'd declare "a pointer to an array of 2 of array of 2
doubles" ...

Tom
 
K

Keith Thompson

Michael said:
I've a couple of (automatically) created functions that take
2-dimensional array as inputs, like

void getMatrix( double M[2][2] )
{
M[0][0] = 1;
M[0][1] = 0;
M[1][0] = 0;
M[1][1] = 1;
}
[snip]

No, you don't have a function with a 2-dimensional array as a
parameter, because there's no such thing in C as an array parameter.

Yes, you have something that *looks* like an array parameter,
but it really isn't. The parameter declaration
double M[2][2]
is quietly translated to
double (*M)[2]
i.e., M is really a pointer to an array of 2 doubles. Typically, it
will point to the first element of an array of arrays of 2 doubles.
The second "2" in the parameter declaration is silently ignored.
 
M

Michael

Thanks for your fast answer,
I've a couple of (automatically) created functions that take
2-dimensional array as inputs, like

void getMatrix( double M[2][2] )
{
M[0][0] = 1;
M[0][1] = 0;
M[1][0] = 0;
M[1][1] = 1; }

The size of the matrices varies: 2x2, 3x2, etc. but is always defined
in the function header.

Well, sort of. The first [2] is just decoration, the second [2]
actually matters. After "decay," the parameter of getMatrix() is
a pointer, whose target type is array-of-two-double.
The functions I deal with are generated by an other program,
which put both numbers there. Of course the
"getMatrix"-thing wasn't, but just entered by hand so I
could left the first one. Sorry for that but I thought it
would be better to stick close to the real situation.
I don't need all matrices simultaneously. Is it allowed to pass an
array that has larger dimensions (i.e. those of the largest matrix)
than specified in the function header? Currently I tried this:
============================================================
#include <stdio.h>

void getMatrix( double M[2][2] );


void getMatrix( double M[2][2] )
{
M[0][0] = 1;
M[0][1] = 0;
M[1][0] = 0;
M[1][1] = 1; };

Stray semicolon.
Thanks, removed.
int main( void )
{
double A[3][3];

void (*fnc)(double M[][]) = getMatrix;

No good, because you get only one level of "decay." This line
tries to declare fnc as a pointer to a function whose parameter is
a pointer to an array of unknown size -- not a pointer to the first
element of such an array, but a pointer to the entire array. Since
the array's size is unknown, it's an "incomplete type."

The parameter of getMatrix() is not a pointer to an array of an
unknown number of double elements, but a pointer to an array of two
double elements. Thus, the type of getMatrix() disagrees with the
type of function fcn is supposed to point at. You ought to get a
diagnostic here.
I invoked gcc with the following options:
<gcc -W -Wall -pedantic -ansi testarray.c>
the version is <gcc --version> --> 2.95.3
Nothing newer available (ansi added afterwards, it warns
about the semicolon).
... but if the code compiled anyhow, this is undefined behavior.
You're calling a function of one type through a pointer to functions
of a different type, and that's a no-no.
Ok, thank you. I had that strange feeling, because without
that conversion the diagnostic triggered.
C's handling of multi-dimensional arrays is a bit clumsy, and can
make trouble in situations like yours. The comp.lang.c Frequently
Asked Questions (FAQ) list at <http://www.c-faq.com/> may prove useful,
particularly Questions 6.19 and 6.21 -- it's probably worth your while
to look at all of Section 6.
I read Q6.19 but since I would like to leave the elsewhere
generated code untouched, the suggested 1D array doesn't
work for me. Is keeping a bunch of arrays as buffers then
the way to go (without that function pointer thing of
course) or exists an other solution?

Thanks again,

Michael
 
K

Keith Thompson

pete said:
Keith said:
Michael said:
I've a couple of (automatically) created functions that take
2-dimensional array as inputs, like

void getMatrix( double M[2][2] )
[...]

No, you don't have a function with a 2-dimensional array as a
parameter, because there's no such thing in C as an array parameter.

Yes, you have something that *looks* like an array parameter,
but it really isn't. The parameter declaration
double M[2][2]
is quietly translated to
double (*M)[2]
i.e., M is really a pointer to an array of 2 doubles. Typically, it
will point to the first element of an array of arrays of 2 doubles.
The second "2" in the parameter declaration is silently ignored.

The *first* "2" in the parameter declaration is silently ignored.

Quite right.
this compiles without warnings:

/* BEGIN this.c */

void func(double M[1][2]);
void func(double M[2][2]);
void func(double (*M)[2]);

/* END this.c */

Yup.

Here's how I convinced myself you're right:

% cdecl
Type `help' or `?' for help
cdecl> declare M as array 10 of array 20 of double
double M[10][20]
cdecl> declare M as pointer to array 20 of double
double (*M)[20]
cdecl>
%
 
B

Ben Bacarisse

Michael said:
Tom said:
int main( void )
{
double A[3][3];

void (*fnc)(double M[][]) = getMatrix;

(*fnc)( A );

printf("[ %.1f, %.1f]\n", A[0][0], A[0][1]);
printf("[ %.1f, %.1f]\n", A[0][2], A[1][0]);

return 0;}

Probably the easier way to do this sort of anonymous thing is use a 1D
array then access it via macro

#define M(i, j) R[i*width+j]

Where "width" is a constant that the compiler can optimize [e.g. *4 ==
<<2 and so on, or more importantly just access the array with known
offsets if it unrolls your code or whatever].

Thanks for your fast reply. If I got it right, you suggest to avoid
the use of a 2D array and stick to 1d one. Properly I missed your
point how to implement it, but does it require a change in getMatrix?

I didn't mentioned it clearly in the first posting: the "getMatrix"
function is generated "somewhere else". Thus, I have no control
there. I could post process the function and try to change the
definitions, but i would prefer to leave these functions untouched.

Can you change the type? If so there is another way: and array of
pointers -- each one points to the start of a 1D array. Access looks
exactly the same so the body of the getMatrix code is the same.

The advantage is that you can access the 2x2 part of, say, a 3x3
matrix seamlessly this way (which, unless I've misread the situation
is you problem). The down side is that it is more complex to allocate
and free such things.

Forgive me for not saying more now, but since it may not be a solution
it seems a waste of time to explain it in detail.

<snip>
 
M

Michael

Ben said:
Michael said:
Tom said:
int main( void )
{
double A[3][3];

void (*fnc)(double M[][]) = getMatrix;

(*fnc)( A );

printf("[ %.1f, %.1f]\n", A[0][0], A[0][1]);
printf("[ %.1f, %.1f]\n", A[0][2], A[1][0]);

return 0;}
Probably the easier way to do this sort of anonymous thing is use a 1D
array then access it via macro

#define M(i, j) R[i*width+j]

Where "width" is a constant that the compiler can optimize [e.g. *4 ==
<<2 and so on, or more importantly just access the array with known
offsets if it unrolls your code or whatever].
Thanks for your fast reply. If I got it right, you suggest to avoid
the use of a 2D array and stick to 1d one. Properly I missed your
point how to implement it, but does it require a change in getMatrix?

I didn't mentioned it clearly in the first posting: the "getMatrix"
function is generated "somewhere else". Thus, I have no control
there. I could post process the function and try to change the
definitions, but i would prefer to leave these functions untouched.

Can you change the type? If so there is another way: and array of
pointers -- each one points to the start of a 1D array. Access looks
exactly the same so the body of the getMatrix code is the same.

The advantage is that you can access the 2x2 part of, say, a 3x3
matrix seamlessly this way (which, unless I've misread the situation
is you problem). The down side is that it is more complex to allocate
and free such things.

Hi, well that sounds good to me. I cannot change the the
type during the "creation" of the function, but it looks to
me that I can do the change afterwards automatically. So the
solution would look like this?
=============================================================
#include <stdio.h>
#include <stdlib.h>
/*Maybe drop the 2 in next 2 lines?*/
void getMatrix( double *M[2] );
void getMatrix( double *M[2] )
{
M[0][0] = 1;
M[0][1] = 0;
M[1][0] = 0;
M[1][1] = 1;
}
int main( void )
{
int nI;
double *A[3];

for( nI=0; nI<3; nI++)
A[nI] = malloc( 3*sizeof(*A[nI]));

if( (A[0] != NULL) && (A[1] != NULL) &&( A[2] != NULL) )
{
getMatrix( A );

printf("[ %.1f, %.1f]\n", A[0][0], A[0][1]);
printf("[ %.1f, %.1f]\n", A[1][0], A[1][1]);
}

for( nI=0; nI<3; nI++)
free(A[nI]);

return 0;
}
=============================================================
Well, then also Q.6.19 is on topic as Eric mentioned. So
thanks there again. Since it is a 1D array can I drop the
number in said:
Forgive me for not saying more now, but since it may not be a solution
it seems a waste of time to explain it in detail.

I'm perfectly happy with your response. You already (like
all others) spend time to help me, which I really
appreciate. Thanks for support again.

Regards,
Michael
 
M

Michael

Keith said:
pete said:
Keith said:
I've a couple of (automatically) created functions that take
2-dimensional array as inputs, like

void getMatrix( double M[2][2] ) [...]
No, you don't have a function with a 2-dimensional array as a
parameter, because there's no such thing in C as an array parameter.

Yes, you have something that *looks* like an array parameter,
but it really isn't. The parameter declaration
double M[2][2]
is quietly translated to
double (*M)[2]
i.e., M is really a pointer to an array of 2 doubles. Typically, it
will point to the first element of an array of arrays of 2 doubles.
The second "2" in the parameter declaration is silently ignored.
The *first* "2" in the parameter declaration is silently ignored.

Quite right.
this compiles without warnings:

/* BEGIN this.c */

void func(double M[1][2]);
void func(double M[2][2]);
void func(double (*M)[2]);

/* END this.c */

Yup.

Here's how I convinced myself you're right:

% cdecl
Type `help' or `?' for help
cdecl> declare M as array 10 of array 20 of double
double M[10][20]
cdecl> declare M as pointer to array 20 of double
double (*M)[20]
cdecl>
%
Thanks to you two for clarifying that.

Regards,

Michael
 
B

Ben Bacarisse

Michael said:
Ben said:
Michael said:
Tom St Denis wrote:
int main( void )
{
double A[3][3];

void (*fnc)(double M[][]) = getMatrix;

(*fnc)( A );

printf("[ %.1f, %.1f]\n", A[0][0], A[0][1]);
printf("[ %.1f, %.1f]\n", A[0][2], A[1][0]);

return 0;}
Probably the easier way to do this sort of anonymous thing is use a 1D
array then access it via macro

#define M(i, j) R[i*width+j]

Where "width" is a constant that the compiler can optimize [e.g. *4 ==
<<2 and so on, or more importantly just access the array with known
offsets if it unrolls your code or whatever].
Thanks for your fast reply. If I got it right, you suggest to avoid
the use of a 2D array and stick to 1d one. Properly I missed your
point how to implement it, but does it require a change in getMatrix?

I didn't mentioned it clearly in the first posting: the "getMatrix"
function is generated "somewhere else". Thus, I have no control
there. I could post process the function and try to change the
definitions, but i would prefer to leave these functions untouched.

Can you change the type? If so there is another way: and array of
pointers -- each one points to the start of a 1D array. Access looks
exactly the same so the body of the getMatrix code is the same.

The advantage is that you can access the 2x2 part of, say, a 3x3
matrix seamlessly this way (which, unless I've misread the situation
is you problem). The down side is that it is more complex to allocate
and free such things.

Hi, well that sounds good to me. I cannot change the the type during
the "creation" of the function, but it looks to me that I can do the
change afterwards automatically.

I'm sorry, but I don't understand this. However, I don't really need
to! If the solution works for you, then I'm happy.
So the solution would look like this?
=============================================================
#include <stdio.h>
#include <stdlib.h>
/*Maybe drop the 2 in next 2 lines?*/
void getMatrix( double *M[2] );
void getMatrix( double *M[2] )

Yes, see later. Note that there is no point in writing a prototype
for a function just before a "full" definition of it (though it does
no harm either). You /can/ define a function in such a way that it
doesn't act as a prototype as well, but why would you?
{
M[0][0] = 1;
M[0][1] = 0;
M[1][0] = 0;
M[1][1] = 1;
}
int main( void )
{
int nI;
double *A[3];

for( nI=0; nI<3; nI++)
A[nI] = malloc( 3*sizeof(*A[nI]));

You can, if you like, do one allocation of 9 items and set three
pointers into that one allocation. I might do it like this:

if ((A[0] = malloc(rows * columns * sizeof *A[0])) != NULL)
for (r = 1; r < rows; r++)
A[r] = &A[columns * r];

For one thing, it simplifies the test of malloc's return result.
if( (A[0] != NULL) && (A[1] != NULL) &&( A[2] != NULL) )
{
getMatrix( A );

printf("[ %.1f, %.1f]\n", A[0][0], A[0][1]);
printf("[ %.1f, %.1f]\n", A[1][0], A[1][1]);
}

for( nI=0; nI<3; nI++)
free(A[nI]);

return 0;
}
=============================================================
Well, then also Q.6.19 is on topic as Eric mentioned. So thanks there
again. Since it is a 1D array can I drop the number in
<<getMatrix>>?

Yup. In fact, some people prefer to write:

void getMatrix( double M[][] ) { ... }

because it makes the "arrayness" more explicit. You can also write:

void getMatrix( double *M[] ) { ... }
void getMatrix( double **M ) { ... }

which are all essentially the same. I've never been able to decide
which is the best -- probably because it does not matter!

I'm perfectly happy with your response. You already (like all others)
spend time to help me, which I really appreciate. Thanks for support
again.

You're welcome.
 
M

Michael

Ben said:
Michael said:
Ben said:
Tom St Denis wrote:
int main( void )
{
double A[3][3];

void (*fnc)(double M[][]) = getMatrix;

(*fnc)( A );

printf("[ %.1f, %.1f]\n", A[0][0], A[0][1]);
printf("[ %.1f, %.1f]\n", A[0][2], A[1][0]);

return 0;}
Probably the easier way to do this sort of anonymous thing is use a 1D
array then access it via macro

#define M(i, j) R[i*width+j]

Where "width" is a constant that the compiler can optimize [e.g. *4 ==
<<2 and so on, or more importantly just access the array with known
offsets if it unrolls your code or whatever].
Thanks for your fast reply. If I got it right, you suggest to avoid
the use of a 2D array and stick to 1d one. Properly I missed your
point how to implement it, but does it require a change in getMatrix?

I didn't mentioned it clearly in the first posting: the "getMatrix"
function is generated "somewhere else". Thus, I have no control
there. I could post process the function and try to change the
definitions, but i would prefer to leave these functions untouched.
Can you change the type? If so there is another way: and array of
pointers -- each one points to the start of a 1D array. Access looks
exactly the same so the body of the getMatrix code is the same.

The advantage is that you can access the 2x2 part of, say, a 3x3
matrix seamlessly this way (which, unless I've misread the situation
is you problem). The down side is that it is more complex to allocate
and free such things.
Hi, well that sounds good to me. I cannot change the the type during
the "creation" of the function, but it looks to me that I can do the
change afterwards automatically.

I'm sorry, but I don't understand this. However, I don't really need
to! If the solution works for you, then I'm happy.
oops, let me have an other try: I get a function (getMatrix
like) completely as source with header file. I cannot change
the way the code is created. The definition of the matrix
will always be done in the M[X][Y] style.
But of course I can run a script that parses the code and
change
"double M[X][Y]"
in the parameter list to
"double *M[]".
Thats why I am so happy that the modification only affects
one line. (I know it would be better to refactor(?) the code
but i lack a good tool and this might be off topic here).
-- Hmm, I'm not sure if this explains the situation better.

So the solution would look like this?
=============================================================
#include <stdio.h>
#include <stdlib.h>
/*Maybe drop the 2 in next 2 lines?*/
void getMatrix( double *M[2] );
void getMatrix( double *M[2] )

Yes, see later. Note that there is no point in writing a prototype
for a function just before a "full" definition of it (though it does
no harm either). You /can/ define a function in such a way that it
doesn't act as a prototype as well, but why would you?

Ok, point taken :). I once copied a bunch of
warnings-switches posted in this group to my makefile
including "-Wmissing-prototypes". I fear i added the line
just to suppress the warning.
{
M[0][0] = 1;
M[0][1] = 0;
M[1][0] = 0;
M[1][1] = 1;
}
int main( void )
{
int nI;
double *A[3];

for( nI=0; nI<3; nI++)
A[nI] = malloc( 3*sizeof(*A[nI]));

You can, if you like, do one allocation of 9 items and set three
pointers into that one allocation. I might do it like this:

if ((A[0] = malloc(rows * columns * sizeof *A[0])) != NULL)
for (r = 1; r < rows; r++)
A[r] = &A[columns * r];

For one thing, it simplifies the test of malloc's return result.
I'll do this, sounds good. Thank you (and all others of
course) for support.

Regards,
Michael
 
M

Michael

Hi Ben,

sorry to bother you again, but in the fragment:
int main( void )
{
int nI;
double *A[3];

for( nI=0; nI<3; nI++)
A[nI] = malloc( 3*sizeof(*A[nI]));

You can, if you like, do one allocation of 9 items and set three
pointers into that one allocation. I might do it like this:

if ((A[0] = malloc(rows * columns * sizeof *A[0])) != NULL)
for (r = 1; r < rows; r++)
A[r] = &A[columns * r];
^^
is the "&" correct?

Regards,

Michael
 
B

Ben Bacarisse

Michael said:
sorry to bother you again, but in the fragment:
int main( void )
{
int nI;
double *A[3];

for( nI=0; nI<3; nI++)
A[nI] = malloc( 3*sizeof(*A[nI]));

You can, if you like, do one allocation of 9 items and set three
pointers into that one allocation. I might do it like this:

if ((A[0] = malloc(rows * columns * sizeof *A[0])) != NULL)
for (r = 1; r < rows; r++)
A[r] = &A[columns * r];
^^
is the "&" correct?

Good spot. The & is kinda right. I intended to say:

A[r] = &A[0][columns * r];

which is probably just as simple to understand if written like this:

A[r] = A[0] + columns * r;

Often people write this:

A[r] = A[r-1] + columns;

or

A[r] = &A[r-1][columns];

so that no multiplication is needed.
 
D

David Thompson

On Fri, 30 Oct 2009 13:32:08 +0000, Ben Bacarisse

Yup. In fact, some people prefer to write:

void getMatrix( double M[][] ) { ... }

because it makes the "arrayness" more explicit. You can also write:
Not standardly. In C89 it *may* work; the element type must be
complete (i.e. not itself array-of-unspecified), but it is not clear
if that is enforced before or after the 'adjustment' of an array
parameter to pointer (and pointer to array-of-unspecified is OK).
I have in fact had implementations go both ways on this point.

In C99 it is now a constraint on the declarator, which strongly
implies that it is illegal before the adjustment. Of course after
generating the required diagnostic, the compiler can continue to give
the same quite reasonable meaning that was allowed in C89.
void getMatrix( double *M[] ) { ... }
void getMatrix( double **M ) { ... }

which are all essentially the same. I've never been able to decide
which is the best -- probably because it does not matter!
No. Both of these are actually pointer to one or more pointer(s), each
to one or more double, i.e. pointer to row-pointer(s). That is a quite
different thing than an actual 2D-array or array-of-array, although
you can access both of them with two subscripts similarly in C. I like
to call this a *2-level* (or *N-level*) array to distinguish it.
 
B

Ben Bacarisse

David Thompson said:
On Fri, 30 Oct 2009 13:32:08 +0000, Ben Bacarisse

Yup. In fact, some people prefer to write:

void getMatrix( double M[][] ) { ... }

because it makes the "arrayness" more explicit. You can also write:
Not standardly. In C89 it *may* work; the element type must be
complete (i.e. not itself array-of-unspecified), but it is not clear
if that is enforced before or after the 'adjustment' of an array
parameter to pointer (and pointer to array-of-unspecified is OK).
I have in fact had implementations go both ways on this point.

Just so I am clear, the "both" ways you refer to are:

(a) silently accepting the parameter's type as if it have been
written double (*M)[] and

(b) complaining the array element type is not complete?
In C99 it is now a constraint on the declarator,

Ah, yes. I missed this point entirely. Thanks.

<snip>
 
D

David Thompson

David Thompson said:
On Fri, 30 Oct 2009 13:32:08 +0000, Ben Bacarisse
void getMatrix( double M[][] ) { ... }
Not standardly. In C89 it *may* work; the element type must be
complete (i.e. not itself array-of-unspecified), but it is not clear
if that is enforced before or after the 'adjustment' of an array
parameter to pointer (and pointer to array-of-unspecified is OK).
I have in fact had implementations go both ways on this point.

Just so I am clear, the "both" ways you refer to are:

(a) silently accepting the parameter's type as if it have been
written double (*M)[] and
I won't swear to silent; there may have been a warning; I'm not
religious about avoiding warnings if I satisfy myself it's not a real
problem. But compiling it okay as the (adjusted) pointer type, yes.
(b) complaining the array element type is not complete?

And failing to compile, yes.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,534
Members
45,007
Latest member
obedient dusk

Latest Threads

Top