2017-09-19 1 views
-1

Ich frage mich, was ist die beste Strategie für die Zuweisung von Speicher für eine Struktur mit vielen Zeigern innerhalb.Beste Strategie in dynamischer Zuordnung in C für strcut mit vielen Zeigern

So:

struct Test{ 
    long unsigned int size; 
    double *A; 
    int *B; 
    double *C; 
}; 

Dann könnte ich viele Zuweisungen wie folgt verwenden:

struct Test *alloc_test(long unsigned int size){ 
    struct Test *ans = (struct Test*)malloc(sizeof(struct Test)); 
    if(ans == NULL){ 
     return NULL; 
    } 
    ans->size = size; 
    ans->A = (double *)malloc(sizeof(double)*size); 
    if(ans->A == NULL){ 
     free(ans); 
     return NULL; 
    } 
    ans->B = (int *)malloc(sizeof(int)*size); 
    if(ans->B == NULL){ 
     free(ans->A); 
     free(ans); 
     return NULL; 
    } 
    ans->C = (double *)malloc(sizeof(double)*size); 
    if(ans->C == NULL){ 
     free(ans->A); 
     free(ans->B); 
     free(ans); 
     return NULL; 
    } 
    return ans; 
} 

Oder ich könnte eine einzelne Zuordnung, wie diese USI:

struct Test *alloc_test(long unsigned int size){ 
    long unsigned int mem_size = sizeof(struct Test) + sizeof(double)*2*size + sizeof(int)*size; 
    struct Test *ans = (struct Test*)malloc(mem_size); 
    if(ans == NULL){ 
     return NULL; 
    } 
    ans->size = size; 
    ans->A = ans + sizeof(struct Test); 
    ans->B = ans->A + sizeof(double)*size; 
    ans->C = ans->B + sizeof(int)*size; 
    return ans; 
} 

Diese Dies ist in diesem Fall möglich, da dieses Objekt nicht erneut zugeordnet werden soll. Kennt jemand in diesem Fall den Vorteil eines jeden?

+0

'ans-> Größe = Größe; ans-> A = ans + Größe von (Struct Test); ans-> B = ans-> A + Größevon (doppelt) * Größe; ans-> C = ans-> B + sizeof (int) * Größe; 'ist die falsche Zeigermathematik. Von diesem Ansatz abraten. – chux

+0

Der Zeiger des zweiten Ansatzes ist falsch. Müsste etwas wie 'ans-> A = (void *) (ans + 1) verwenden; ans-> B = (void *) (ans-> A + Größe); ans-> C = (void *) (ans-> B + Größe); '. Dies stellt jedoch die wichtigen Ausrichtungsprobleme außer Kraft, die weitere Codeanpassungen erforderten. Es empfiehlt sich, die zweite Methode erst dann zu verwenden, wenn die Mathematik und Ausrichtung des Masters beherrscht werden. – chux

Antwort

3

Beides ist möglich, und das, was Sie wählen, ist Ihre Freiheit. Sie sollten jedoch alignment Einschränkungen gehorchen (vielleicht alignas und alignof von <stdalign.h> für die Einzelbelegung Variante)

Lesen Sie auch über flexible array members, die ein einziges malloc in dem besonderen Fall erlaubt haben Sie nur ein Arraymitglied.

Beachten Sie, dass jeder Anruf an malloc seinen Overhead hat (beide im Speicher, vielleicht ein zusätzliches Wort oder zwei für interne Verwaltung und in der Zeit verbrauchen; eine typische malloc dauert weniger als eine Mikrosekunde auf meinem Desktop).

Für langlebige Programme, z.B. Server, die Sie vielleicht auch interessieren fragmentation (kein Problem für die meisten kurzlebigen Anwendungen)

Der zweite Ansatz (Single malloc) könnte etwas mehr cache freundlich sein. Meistens ist es dir egal.

BTW

(wie durch chux kommentierten)
ans->A = ans + sizeof(struct Test); 

ist falsch, weil Zeigerarithmetik in Einheiten des spitzen Typs geschieht. Sie können

ans->A = ((char*)ans)+sizeof(struct Test); 

wollen und eigentlich sollten Sie berechnen mem_size vorsichtiger (auch mit alignof darin, oder der Annahme, dass alignof(long unsigned int) >= alignof(double) und so weiter), dann

char* ad = malloc(mem_size); 
    if (!ad) return NULL; 
    ans = ad; 
    ans->A = ad + sizeof(struct Test); 

Die genaue Berechnung von mem_size (bevorzugen, die benötigt etwas bedingt und mit alignof) und der echte Code ist als Übung übrig (ich bin zu langweilig, um es hier zu erklären).

+0

Ich schien dieses Konzept der Ausrichtung vorher nicht. Also, die beste Praxis ist wirklich die erste. tks – Caio

+0

Was bedeutet "ich nicht dieses Konzept" bedeuten? –

+0

Bedeutet, dass ich falsch geschrieben habe. "Ich hatte das Konzept noch nie gesehen ..." – Caio

3

In Plan A erhalten Sie Memory Fencing, architekturspezifische Speicherausrichtung, Realloc-Fähigkeit. Natürlich könnte man das ein bisschen umgestalten, so dass die Fehlerbehandlung nicht überall verstreut ist - aber das ist eine Frage des persönlichen Stils.

In Plan B verlieren Sie all das automatische Zeug - Sie müssen sich darum kümmern. Dann könnte es sehr schwierig werden, es zu lesen.

Je nach Zuordner können Sie leichter mehrere kleinere Speicherblöcke als einen Mega-Chunk finden. Also, Strategie-weise, müssen Sie Ihre eigene Entscheidung treffen - wenn Sie Ihren eigenen Allokator haben.

1

Lassen Sie mich Ihnen zeigen, wie der Fehler in einem viel sauberer Weise zu handhaben für den ersten Fall:

struct Test *alloc_test(long unsigned int size) 
{ 
    struct Test *ans = malloc(sizeof(struct Test)); 
    if(ans == NULL) 
    { 
     return NULL; 
    } 

    ans->size = size; 
    ans->A = malloc(sizeof(ans->A) * size); 
    ans->B = malloc(sizeof(ans->B) * size); 
    ans->C = malloc(sizeof(ans->C) * size); 

    if(ans->A == NULL || ans->B == NULL || ans->C == NULL) 
    { 
     free(ans->A); 
     free(ans->B); 
     free(ans->C); 
     free(ans); 
     return NULL; 
    } 

    return ans; 
} 
+0

Für klareren Code, könnte verwenden, ans-> A = malloc (sizeof * (ans-> A) * Größe); ', etc Keine Notwendigkeit für Cast und Größe zu den referenzierten Daten. – chux

+0

@chux Sie haben Recht. Ty. Bearbeitet – bolov

0

Sie können überhaupt nicht mehrere Anrufe zu malloc() oder befassen sich mit Ausrichtung verwenden müssen.

Wenn alle dynamisch zugewiesenen Arrays wird immer die gleiche Anzahl von Elementen hat, ein struct verwenden, die die tatsächlichen Werte und Erstellen einen Arrays der struct enthält:

typedef struct data 
{ 
    double A; 
    double B; 
    int C; 
}; 

Allocation:

struct data *dataPtr = malloc(size * sizeof(*dataPtr)); 

Ausplanung:

free(dataPtr); 

Einfach und leicht verständlich.

Wenn Sie die Größe um mit den Daten tragen müssen, verwenden Sie einen struct mit einer flexiblen Anordnung von struct data:

typedef struct test 
{ 
    unsigned long size; 
    struct data[]; 
} 

Allocation:

struct test *testPtr = malloc(sizeof(*testPtr) + size * sizeof(testPtr->data)); 
testPtr ->size = size; 

Ausplanung:

free(testPtr);