98

ベクトルの長さとその値を表す構造を次のように定義するとします。

struct Vector{
    double* x;
    int n;
};

ここで、ベクトル y を定義してメモリを割り当てたいとします。

struct Vector *y = (struct Vector*)malloc(sizeof(struct Vector));

インターネットで検索したところ、x のメモリを個別に割り当てる必要があることがわかりました。

y->x = (double*)malloc(10*sizeof(double));

しかし、y->x にメモリを 2 回割り当てているようで、1 つは y にメモリを割り当てながら、もう 1 つは y->x にメモリを割り当てながら、メモリを無駄にしているようです。コンパイラが実際に何をしているか、y と y->x の両方を初期化する正しい方法を教えていただければ幸いです。

前もって感謝します。

4

8 に答える 8

176

いいえ、メモリを 2 回割り当てているわけy->xではありません。

代わりに、構造体 (ポインターを含む) にメモリを割り当て、さらにそのポインターが指す何かを割り当てます。

次のように考えてください。

         1          2
        +-----+    +------+
y------>|  x------>|  *x  |
        |  n  |    +------+
        +-----+

したがって、すべてを格納するには、実際には 2 つの割り当て (1と) が必要です。2

さらに、型はstruct Vector *yポインターであるため、C からの戻り値をキャストしないでmallocください。隠したくない特定の問題を隠すことができるためです。C は、void*戻り値を他のポインターに暗黙的に変換することが完全に可能です。

そしてもちろん、次のように、これらのベクトルの作成をカプセル化して、管理を容易にしたいと思うでしょう。

struct Vector {
    double *data;    // no place for x and n in readable code :-)
    size_t size;
};

struct Vector *newVector (size_t sz) {
    // Try to allocate vector structure.

    struct Vector *retVal = malloc (sizeof (struct Vector));
    if (retVal == NULL)
        return NULL;

    // Try to allocate vector data, free structure if fail.

    retVal->data = malloc (sz * sizeof (double));
    if (retVal->data == NULL) {
        free (retVal);
        return NULL;
    }

    // Set size and return.

    retVal->size = sz;
    return retVal;
}

void delVector (struct Vector *vector) {
    // Can safely assume vector is NULL or fully built.

    if (vector != NULL) {
        free (vector->data);
        free (vector);
    }
}

このように作成をカプセル化することで、ベクターが完全に構築されているか、まったく構築されていないかを確認できます。また、クライアントに影響を与えることなく、将来的に基礎となるデータ構造を完全に変更することもできます (たとえば、速度のためにスペースをトレードオフするためにそれらを疎な配列にしたい場合)。

于 2013-02-08T08:11:54.197 に答える
5

初めて、メモリを に割り当てます。Vectorこれは、変数x、を意味しますn

ただしx 、まだ有用なものを指していません

そのため、2 番目の割り当ても必要になります

于 2013-02-08T08:11:44.070 に答える
4

原則として、あなたはすでにそれを正しくやっています。あなたがしたいことには、2つmalloc()の s が必要です。

いくつかのコメント:

struct Vector y = (struct Vector*)malloc(sizeof(struct Vector));
y->x = (double*)malloc(10*sizeof(double));

する必要があります

struct Vector *y = malloc(sizeof *y); /* Note the pointer */
y->x = calloc(10, sizeof *y->x);

最初の行では、Vector オブジェクトにメモリを割り当てます。malloc()割り当てられたメモリへのポインタを返すため、y は Vector ポインタでなければなりません。2 行目では、10 個の double の配列にメモリを割り当てます。

C では、明示的なキャストは必要ありません。型の安全性のためには、sizeof *y代わりに書く方が優れています。さらに、入力の手間も省けます。sizeof(struct Vector)

構造体を再配置して、次のmalloc()ように 1 回実行できます。

struct Vector{    
    int n;
    double x[];
};
struct Vector *y = malloc(sizeof *y + 10 * sizeof(double));
于 2013-02-08T08:22:24.230 に答える
3

数点

struct Vector y = (struct Vector*)malloc(sizeof(struct Vector));間違っている

へのポインタを保持しているためstruct Vector *y = (struct Vector*)malloc(sizeof(struct Vector));です。ystruct Vector

1つ目malloc()は、Vector構造(double + intへのポインタ)を保持するのに十分なメモリのみを割り当てます

2番目malloc()は実際にメモリを割り当てて、10 double を保持します。

于 2013-02-08T08:14:12.050 に答える
1

Vector と配列を同時に割り当てることにより、実際には単一の malloc でこれを行うことができます。例えば:

struct Vector y = (struct Vector*)malloc(sizeof(struct Vector) + 10*sizeof(double));
y->x = (double*)((char*)y + sizeof(struct Vector));
y->n = 10;

これにより、Vector 'y' が割り当てられ、y->x が Vector 構造体の直後 (ただし、同じメモリ ブロック内) に割り当てられた余分なデータを指すようになります。

ベクトルのサイズ変更が必要な場合は、推奨される 2 つの割り当てで行う必要があります。内部 y->x 配列は、ベクトル構造体 'y' をそのまま維持しながらサイズを変更できます。

于 2013-02-08T08:17:29.783 に答える
1

メモリを割り当てるときはstruct Vector、ポインタxにメモリを割り当てるだけです。つまり、アドレスを含むその値が配置されるスペースにメモリを割り当てます。そのため、参照するブロックにメモリを割り当てませんy.x

于 2013-02-08T08:11:28.080 に答える
1

最初の malloc は、x (double へのポインタ) のメモリを含む、struct のメモリを割り当てます。2 番目の malloc は、x が指す double 値にメモリを割り当てます。

于 2013-02-08T08:11:56.973 に答える
-1

構造体のフルサイズにメモリを自動的に割り当てる場合malloc(sizeof(struct_name))、内部の各要素を malloc する必要はありません。

-fsanitize=addressフラグを使用して、プログラム メモリをどのように使用したかを確認します。

于 2020-11-20T00:26:25.150 に答える