Question

I have declared a struct, and I try to pass an array of those structs (as well as a double array of doubles, and an integer) into a function. I get an "array type has incomplete element type" message from gcc when I compile it. What have I gotten wrong in how I pass the struct to the function?

typedef struct graph_node {
  int X;
  int Y;
  int active;
} g_node;

void print_graph(g_node graph_node[], double weight[][], int nodes);

I have also tried struct g_node graph_node[], but I get the same thing.

Was it helpful?

Solution

It's the array that's causing trouble in:

void print_graph(g_node graph_node[], double weight[][], int nodes);

The second and subsequent dimensions must be given:

void print_graph(g_node graph_node[], double weight[][32], int nodes);

Or you can just give a pointer to pointer:

void print_graph(g_node graph_node[], double **weight, int nodes);

However, although they look similar, those are very different internally.

If you're using C99, you can use variably-qualified arrays. Quoting an example from the C99 standard (section §6.7.5.2 Array Declarators):

void fvla(int m, int C[m][m]); // valid: VLA with prototype scope

void fvla(int m, int C[m][m])  // valid: adjusted to auto pointer to VLA
{
    typedef int VLA[m][m];     // valid: block scope typedef VLA
    struct tag {
        int (*y)[n];           // invalid: y not ordinary identifier
        int z[n];              // invalid: z not ordinary identifier
    };
    int D[m];                  // valid: auto VLA
    static int E[m];           // invalid: static block scope VLA
    extern int F[m];           // invalid: F has linkage and is VLA
    int (*s)[m];               // valid: auto pointer to VLA
    extern int (*r)[m];        // invalid: r has linkage and points to VLA
    static int (*q)[m] = &B;   // valid: q is a static block pointer to VLA
}

Question in comments

[...] In my main(), the variable I am trying to pass into the function is a double array[][], so how would I pass that into the function? Passing array[0][0] into it gives me incompatible argument type, as does &array and &array[0][0].

In your main(), the variable should be:

double array[10][20];

or something faintly similar; maybe

double array[][20] = { { 1.0, 0.0, ... }, ... };

You should be able to pass that with code like this:

typedef struct graph_node
{
    int X;
    int Y;
    int active;
} g_node;

void print_graph(g_node graph_node[], double weight[][20], int nodes);

int main(void)
{
    g_node g[10];
    double array[10][20];
    int n = 10;

    print_graph(g, array, n);
    return 0;
}

That compiles (to object code) cleanly with GCC 4.2 (i686-apple-darwin11-llvm-gcc-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.9.00)) and also with GCC 4.7.0 on Mac OS X 10.7.3 using the command line:

/usr/bin/gcc -O3 -g -std=c99 -Wall -Wextra -c zzz.c

OTHER TIPS

The compiler needs to know the size of the second dimension in your two dimensional array. For example:

void print_graph(g_node graph_node[], double weight[][5], int nodes);

Posting this in case someone comes across this question and wonder about the formal reasons why [] works and [][] doesn't, in general. There's various rules in play: the rules of what makes a valid array declaration and the rules of how arrays passed as parameters to functions "decay" into a pointer to the first element.

C17 6.7.6.2/1 Array declarators:

The element type shall not be an incomplete or function type.

In case of double weight[][], the element type is double[], an incomplete (array) type, which isn't allowed to be declared anywhere, parameter or not. Because this rule of array declaration applies before the rule of "array decay" of function parameters, which is found in C17 6.7.6.3/7 Function declarators:

A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to type’’

That rules assumes that we already have a declaration of the array, which would have to be done according the 6.7.6.2 rule previously quoted.

In case of a single dimension array double[], then this is an incomplete array type but the element type is double, which is a complete type. Such an array declaration is allowed according to C17 6.7.6.2/4:

If the size is not present, the array type is an incomplete type.

Whenever such an array is used with an initializer list, double foo[] = { 1.0f }; then C17 6.7.9/22 states that it is given a size depending on the initializers and turns into a complete type by the end of the declaration:

If an array of unknown size is initialized, its size is determined by the largest indexed element with an explicit initializer. The array type is completed at the end of its initializer list.

If it is not initialized, but simply part of a function parameter list, then the previously mentioned rule of "array decay" applies and double[] gets replaced with double*.

Now in case we have an array parameter such as double [][3], then it is an incomplete array type but the element type double [3] is a complete array type, so it's a valid declaration. In that case the parameter gets adjusted to a pointer to such an element type, double (*)[3]. And that's the reason why the left-most array dimension in a multi-dimensional array parameter declaration can be left out - it actually doesn't matter what size we type there.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top