2

C 関数から柔軟な配列メンバーを持つ構造体を返す必要がありますが、コンパイルできない理由がわかりません。次のように配列を構造体にカプセル化することで、配列を返すことができることを私は知っています。

struct data_array {
    long length;
    double data[];
};

私の関数は次のようになります。

struct data_array test (int length) {
    struct data_array a;
    double* b = malloc (1000);
    a.length = 1000;
    a.data = b;
    return a;
}

ただし、コンパイラは「柔軟な配列メンバーの無効な使用」を返します。

本「21st Century C」によると、構造体のデータ配列はポインターとして扱われます (これは私には完全に理にかなっています)。初期化されていないため、データを保持するためのメモリが割り当てられていないはずです。(コンパイラでさえ、必要なメモリ量を知りません)。したがって、メモリを割り当てて、それを戻り変数に割り当てる必要があります。

では、なぜコンパイラはエラーを返すのでしょうか? そして、どうすればこの問題を解決できますか?

4

7 に答える 7

4

data不完全な配列 (指定された次元のない配列) であると宣言するか、ポインターであると宣言することができます。(構造体内の不完全な配列は最後のメンバーである必要があり、柔軟な配列メンバーと呼ばれます。)

不完全な配列であると宣言すると、構造体には基本的にlength要素と、割り当てた数の配列要素が含まれます。次のように、構造体の基本サイズにすべての要素のスペースを加えたものを割り当てる必要があります。

struct data_array *b = malloc(sizeof *b + NumberOfElements * sizeof *b->data);

ただし、柔軟な配列の余分な要素を返す方法がないため、この方法で割り当てられた構造体を返すべきではありません。関数の戻り値の型には、構造体の基本サイズのみが含まれます。ただし、構造体へのポインタを返すことはできます。したがって、戻ることはできますが、戻ることはできbません*b

ポインターであると宣言する場合は、構造体を作成し、次のようにポイントするdataためのスペースを個別に割り当てます。data

struct data_array b;
b.length = NumberOfElements;
b.data = malloc(NumberOfElements * sizeof *b.data);

コードサンプルを次に示します。まず、柔軟な配列メンバーを使用します。

struct data_array
{
    long length;
    double data[];
};

struct data_array *test(size_t NumberOfElements)
{
     struct data_array *b = malloc(sizeof *b + NumberOfElements * sizeof *b->data);
     // Put code here to test the result of malloc.
     b->length = NumberOfElements;
     return b;
}

またはポインタを使用して:

struct data_array
{
    long length;
    double *data;
};

struct data_array test(size_t NumberOfElements)
{
     struct data_array b = { NumberOfElements,
         malloc(sizeof *b + NumberOfElements * sizeof *b->data) };
     // Put code here to test the result of malloc.
     return b;
}
于 2013-07-18T13:30:46.340 に答える
0

あなたのような柔軟な配列メンバーを持つ構造体 (data構造体定義でサイズが指定されていない) は、次のように割り当てられます。

struct data_array *a;   // pointer!!
a = malloc( sizeof(struct data_array) + 1000 * sizeof(double) );

sizeof(struct data_array)除外する構造体の定数サイズはどこdataにあり1000、目的の配列サイズはどこにありますか。もちろんdataポインタに変更して別途配置することもできますが、それは少し違います。

于 2013-07-18T13:30:14.590 に答える
0

いくつかのこと:

1) 構造体の定義を次のように変更します。

 struct data_array {
    long length;
    double* data;
          ^
};

2) これは、配列にメモリを割り当てるために malloc を使用する方法です。

a.data =  malloc (length * sizeof(double));

編集

間違いが多すぎます。次のコードに従ってください。

#include <stdio.h>
#include <stdlib.h>
struct data_array {
    long length;
    double* data;
};
struct data_array* test (int length) {
    struct data_array* a;
    a = malloc (sizeof (data_array));
    a->data = malloc (length*sizeof(double));
    a->length = length;
    return a;
}

int main () {
    data_array* x;
    x = test (5);
    for (int i=0; i<5; i++) {
        x->data[i] = i+0.5;
    }
    for (int i=0; i<5; i++) {
        printf ("%f\n" , x->data[i]);
    }
}

malloc を使用する場合は、型にキャストを追加する必要がある場合があることに注意してください (視覚的にそうするように強制されます。そうしないと、コンパイル エラーになります。しかし、単に磨耗しています)。

于 2013-07-18T13:31:12.143 に答える
0
struct data_array * test(long length) {
    struct data_array *a = calloc(1,sizeof(struct data_array) + length*sizeof(double));
    a->length = length;
    return a;
}
于 2013-07-18T13:35:28.047 に答える
0

私はgccを使用していますが、この方法で問題ないと思います:

struct data_array {
    long length;
    double* data;
};
struct data_array* test (int length) {
    struct data_array* a =(struct data_array *) malloc (sizeof (data_array));
    a->data = malloc (length*sizeof(double));
    a->length = length;
    return a;
}
于 2013-07-18T15:34:20.783 に答える
0

に変換できない理由については、以前に尋ねられたこの質問を参照してdouble*ください。double[]

問題を解決するには、に変更double data[];するdouble *data;とうまくいきます。

新しいアップデート:

double* b = malloc(sizeof(double) * 1000);
于 2013-07-18T13:26:21.527 に答える
0

行の配列のベースアドレスを変更しようとしています

a.data = b;

配列のベース アドレスを変更することはできません。配列のベース アドレスは定数ポインタです。

于 2013-07-18T13:22:38.747 に答える