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

问题描述 投票:0回答:4

我已经声明了一个

struct
,并且尝试将这些结构的数组(以及
double
双精度数组和一个整数)传递到函数中。当我编译它时,我收到来自 gcc 的 “数组类型具有不完整的元素类型” 消息。我在将
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[]
,但我得到了同样的结果。

arrays c gcc multidimensional-array incomplete-type
4个回答
44
投票

数组造成了麻烦:

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 数组声明符部分):

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
}

评论里有问题

[...] 在我的 main() 中,我尝试传递到函数中的变量是

double array[][]
,那么我如何将其传递到函数中呢?将
array[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

10
投票

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

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

3
投票

发布此内容是为了防止有人遇到这个问题并想知道为什么

[]
有效而
[][]
一般来说不起作用的正式原因。有各种各样的规则在起作用:有效数组声明的规则以及数组如何作为参数传递给函数的规则“衰减”为指向第一个元素的指针。

C17 6.7.6.2/1 数组声明符:

元素类型不得是不完整类型或函数类型。

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

将参数声明为“类型数组”应调整为“指向的限定指针” 输入’’

该规则假设我们已经有了数组的声明,这必须根据前面引用的 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]
。这就是为什么多维数组参数声明中最左边的数组维度可以被省略的原因 - 实际上我们在那里输入什么大小并不重要。


0
投票

如果您在 Leetcode 代码编辑器中遇到此错误,请重置为默认代码定义,然后就可以开始了。我也遇到了同样的问题,重置解决了我的问题。

© www.soinside.com 2019 - 2024. All rights reserved.