3

次のように定義されたデータ構造があります。

struct varr {
    int n; //length of data array
    double data[];
};

データ配列は、最初はサイズ1である必要がありますが、増加する可能性があります。

struct varr *私が使用するスペースを割り当てるとき

struct varr *p = malloc(sizeof(struct varr) + sizeof(double));

スペースを再割り当てしてデータ配列のサイズを増やすとき、私は使用します

p = realloc(p, sizeof(struct varr) + p->n * sizeof(double));//p->n having already been set

私の質問は、「この構造に割り当てられたメモリをどのように解放する必要があるか」です。

簡単なことを試しましたfree(p);が、memcheckによるとこれによりメモリリークが発生します。この目的のためにデータを構造化する方法、またはメモリを割り当てる方法に根本的な問題がありますか?

==注==

明示的に宣言された配列の代わりにポインターを使用することで問題を解決しました。しかし、なぜこれが機能しないのかについての簡潔な答えにまだ興味があります。

4

3 に答える 3

5

ご存知かもしれませんが、mallocOSを呼び出すたびにメモリが確保され、サイズと属性が記憶されます。したがって、を呼び出すとfree、配列またはポインタの両方をクリアできます。

例:

char* array = malloc(16 * sizeof(char));
char* single = malloc(sizeof(char));

free(array);
free(single);

ご覧のとおり、常に1free対1で取得できますmalloc。これは、OSが割り当てたバイト数を認識しているため、OSがどのタイプであり、作成されたインスタンスの数を気にしないためです。(注:アプリケーションは実行するデストラクタを知る必要があるため、C ++deleteとでは違いがあるのはこのためです。クリーンアップの制御はOSだけに任されていません...)delete[]

ここから、単一のを使用して構造体を1つのブロックとして割り当てた場合、単一の呼び出しmallocを使用して構造体を解放できると想定できます。free

この例は、リークなしで機能します。

#include <stdlib.h>

typedef struct Array_t
{
    int Length;
    double Data[];
} Array;

Array* create_array(int length)
{
    Array* array = malloc(sizeof(Array) + length * sizeof(double));
    if (array != NULL)
        array->Length = length;

    return array;
}

void delete_array(Array* array)
{
    free(array);
}

int main()
{
    Array* array = create_array(100);
    if (array == NULL)
        return EXIT_FAILURE;

    for (int i = 0; i < array->Length; ++i)
    {
        array->Data[i] = 1.7 * (i + 3);
    }

    delete_array(array);

    return EXIT_SUCCESS;
}

もちろん、JohnFindlayの例のようなもっと複雑なものに出くわした場合

struct SomeStruct
{
    int Size;
    int* ArrayOfPointers[];
}

この構造体は1つで作成できますmalloc。例:

// *s* contains an array of 14 int pointers (int*)
struct SomeStruct* s = malloc(sizeof(SomeStruct) + 14 * sizeof(int*));
s->Size = 14;

コアの問題は、それint* ArrayOfPointersがポインタの配列であるということです。したがって、適切に初期化するには、次のことも行う必要があります。

// each of the *s*'s int pointers is actually a decayed array of 25 ints
for (int i = 0; i < s->Size; ++i)
    s->ArrayOfPointers[i] = malloc(25 * sizeof(int));

そして解放するとき:

for (int i = 0; i < s->Size; ++i)
    free(s->ArrayOfPointers[i]);

free(s);

ただし、重要なのは、FAMを使用した構造が1回のfree呼び出しで解放されるということです。ループは、割り当てられたポインタデータを解放します。これは、動的に割り当てられた2D配列を解放することと同じです。

于 2015-03-01T10:04:10.973 に答える
3

それは完全に間違っているように見えます。私はそれがこのようになるべきだと思います:

// step 1: Allocate n items:

struct varr * p = malloc(sizeof *p + n * sizeof(double));
if (p) { p->n = n; }

// step 2: Reallocate to hold m items:

struct varr * tmp = realloc(p, sizeof *tmp + m * sizeof(double));
if (tmp) { p = tmp;  p->n = m; }

終わったら、言うのを忘れないでくださいfree(p);

于 2012-11-15T04:36:56.800 に答える
0

私は昨夜同じ問題に遭遇しました。数時間のグーグルの後、私はこれを見つけました。チュートリアルでは非常に単純ですが賢い答えです。

void free_struct( THESTRUCT * ts )
{
// free all memory accoiated with our structure
if(ts){
    for(int i = 0; i<ts->count; i++)
        free(ts->str[i]);
    free(ts);
    }
}

http://www.johnfindlay.plus.com/lcc-win32/Tuts/FlexArrs.htm

于 2014-09-26T12:14:53.530 に答える