34

を宣言し、それらの構造体の配列(およびdoubleの配列と整数)を関数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[]ましたが、同じことがわかります。

4

3 に答える 3

38

次の問題を引き起こしているのはアレイです。

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

2番目以降の次元を指定する必要があります。

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[][]、それを関数に渡すにはどうすればよいですか?それに渡すと、andと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.ビルド5658に基づく)(LLVMビルド2336.9.00))およびGCCで(オブジェクトコードに)クリーンにコンパイルされます。コマンドラインを使用したMacOSX10.7.3の4.7.0:

/usr/bin/gcc -O3 -g -std=c99 -Wall -Wextra -c zzz.c
于 2012-04-04T00:35:12.803 に答える
9

コンパイラは、2次元配列の2番目の次元のサイズを知る必要があります。例えば:

void print_graph(g_node graph_node[], double weight[][5], int nodes);
于 2012-04-04T00:36:58.480 に答える
3

誰かがこの質問に出くわし、一般的に機能する理由と機能しない理由について疑問に思った場合に備えて、これを投稿して[]ください[][]。さまざまなルールがあります。有効な配列宣言を作成するルールと、配列がパラメーターとして関数に渡される方法のルールが、最初の要素へのポインターに「減衰」します。

C17 6.7.6.2 / 1配列宣言子:

要素型は、不完全型または関数型であってはなりません。

の場合double weight[][]、要素タイプはdouble[]、不完全な(配列)タイプであり、パラメーターであるかどうかに関係なく、どこでも宣言することはできません。この配列宣言の規則は、C17 6.7.6.3/7関数宣言子にある関数パラメーターの「配列減衰」の規則の前に適用されるため、次のようになります。

「型の配列」としてのパラメーターの宣言は、「型への修飾ポインター」に調整されるものとします。</ p>

このルールは、配列の宣言がすでにあることを前提としています。これは、前に引用した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]。これが、多次元配列パラメーター宣言の左端の配列次元を省略できる理由です。実際には、そこに入力するサイズは関係ありません。

于 2021-03-02T09:38:44.227 に答える