Arrays GCC:数组类型的元素类型不完整

Arrays GCC:数组类型的元素类型不完整,arrays,c,gcc,multidimensional-array,incomplete-type,Arrays,C,Gcc,Multidimensional Array,Incomplete Type,我声明了一个struct,并尝试将这些结构的数组(以及一个doubledouble数组和一个整数)传递到一个函数中。编译时,我从gcc收到一条“array type has complete element type”消息。在如何将struct传递给函数时,我犯了什么错误 typedef struct graph_node { int X; int Y; int active; } g_node; void print_graph(g_node graph_node[], doub

我声明了一个
struct
,并尝试将这些结构的数组(以及一个
double
double数组和一个整数)传递到一个函数中。编译时,我从gcc收到一条“array type has complete element type”消息。在如何将
struct
传递给函数时,我犯了什么错误

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

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

我也尝试过
struct g_node graph_node[]
,但我得到了同样的结果。

是数组在以下方面造成了问题:

void print_graph(g_node graph_node[], double weight[][], int nodes);
必须给出第二个和后续尺寸:

void print_graph(g_node graph_node[], double weight[][32], int nodes);
或者,您可以只给一个指向指针的指针:

void print_graph(g_node graph_node[], double **weight, int nodes);
然而,尽管它们看起来很相似,但它们在内部却大不相同

如果您使用的是C99,则可以使用可变限定数组。引用C99标准的示例(第§6.7.5.2节阵列声明器):


评论中的问题 […]在我的main()中,我试图传递到函数中的变量是一个
双数组[][]
,那么如何将它传递到函数中呢?将
数组[0][0]
传递给它会给我提供不兼容的参数类型,
&array
&array[0][0]

main()
中,变量应为:

double array[10][20];
或者有点相似的东西;也许吧

double array[][20] = { { 1.0, 0.0, ... }, ... };
您应该能够通过以下代码传递该信息:

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;
}
使用GCC 4.2(i686-apple-darwin11-llvm-GCC-4.2(GCC)4.2.1(基于apple Inc.build 5658)(llvm build 2336.9.00))以及Mac OS X 10.7.3上的GCC 4.7.0(使用命令行)干净地编译(到目标代码):

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

编译器需要知道二维数组中第二维的大小。例如:

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

如果有人遇到这个问题,并且想知道一般情况下,
[]
起作用而
[]]
不起作用的正式原因,请发布此消息。有各种规则在起作用:什么是有效数组声明的规则,以及数组如何作为参数传递给函数“衰减”为指向第一个元素的指针的规则

C17 6.7.6.2/1数组声明器:

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
}
元件类型不得为不完整或功能类型

double weight[][]
的情况下,元素类型为
double[]
,这是一种不完整的(数组)类型,不允许在任何地方声明,无论是否声明参数。因为此数组声明规则适用于函数参数的“数组衰减”规则之前,该规则在C17 6.7.6.3/7函数声明器中找到:

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
}
将参数声明为“类型数组”应调整为“指向 类型“”

该规则假设我们已经有了数组的声明,这必须根据前面引用的6.7.6.2规则来完成

如果是一维数组
double[]
,则这是一种不完整的数组类型,但元素类型是
double
,这是一种完整类型。根据C17 6.7.6.2/4,允许这样的数组声明:

如果大小不存在,则数组类型为不完整类型

每当这样的数组与初始值设定项列表一起使用时,
double foo[]={1.0f}
然后C17 6.7.9/22声明根据初始值设定项为其指定大小,并在声明结束时变为完整类型:

如果初始化了未知大小的数组,则其大小由索引的最大值确定 具有显式初始值设定项的元素。数组类型在其结束时完成 初始化列表

如果未初始化,而只是函数参数列表的一部分,则应用前面提到的“数组衰减”规则,并将
double[]
替换为
double*


现在如果我们有一个数组参数,比如
double[][3]
,那么它是一个不完整的数组类型,但是元素类型
double[3]
是一个完整的数组类型,所以它是一个有效的声明。在这种情况下,参数被调整为指向此类元素类型的指针,
double(*)[3]
。这就是为什么多维数组参数声明中最左边的数组维度可以省略的原因-实际上,我们在那里键入的大小无关紧要。

这正是我所需要的,它可以很好地编译。我还有一个问题,在main()中,我试图传递到函数中的变量是一个“双数组[][]”,那么如何将其传递到函数中呢?将数组[0][0]传递给它会给我不兼容的参数类型,&array和&array[0][0]也是如此。+1回答得很好。还值得一提的是,函数参数
double weight[][10]
double(*weight)[10]
相同,因为函数声明中的数组参数被视为指向第一个元素的指针(这就是为什么不需要提供第一个维度的大小)C89§6.7.1,可能在C99的类似位置。