2017-10-01 1 views
3

ich die struct folgend habeWann nicht-dynamische Arrays in einer Struktur free'd erhält

typedef struct { 
    int id; 
    double c[2]; 
    double p[4][2]; 
} Detection; 

Dies ist der Konstruktor für sie

Detection* create_detection(int i) { 
    Detection* detection = (Detection*) malloc(sizeof(Detection)); 
    detection->id = i; 
    return detection; 
} 

Wie Sie sehen können, die Struktur selbst dynamisch zugewiesen wird . Ich versuche, einen Destruktor dafür zu schreiben, und das habe ich bisher.

void destroy_detection(Detection* detection) { 
    free(detection); 
} 

wird diese kostenlos c und p auch?

Antwort

3

Ich möchte den wichtigen Teil ausdrücklich darauf hinweisen, dass in anderen Antworten impliziert:

Die malloc weiß nicht, was es für Speicher reserviert.

Er empfängt die Anzahl der Bytes als Eingabe und gibt einen Zeiger zurück, der mindestens so viele Bytes adressierbar ist.

Auf meinem Compiler/Maschinenkombination sizeof(Detection) ist 88. So ordnet malloc nur 88-ish Bytes im Heap zu und gibt einen Zeiger darauf zurück. Es liegt in der Verantwortung des Programmierers, diesen Speicher auf eine bestimmte Weise zu interpretieren (und die Verantwortung des Compilers, das Layout der Strukturelemente im Speicher auf korrekte Weise zu unterstützen und den richtigen Code zu generieren, der den richtigen Offset berechnet innerhalb dieses Speichers, um auf diese Mitgliedsdaten zuzugreifen) - in Ihrem Code weisen Sie diese Adresse einem Zeiger auf die Struktur Detection zu. Sie könnten auch versuchen, es einem Zeiger auf eine andere Struktur zuzuordnen, und es funktioniert oder könnte nicht funktionieren (wie im Programm abstürzt und/oder alle Daten auf Ihrem Computer löscht), abhängig von der Strukturgröße und der Menge des zugewiesenen Speichers.

Also, malloc, weiß nicht, dass es Speicher für eine Struktur mit Arrays reserviert. Es weist nur eine kontinuierliche Speicherregion zu, die, wenn sie richtig codiert wird (d. H. Die richtige Größe wird an malloc übergeben), würde ausreichen, um eine Struktur vom Typ Detection zu enthalten.

Wir Ihren Code ein wenig ändern kann (ich ein wenig betrogen, da auf meine Maschinen Größen von long long und double geschehen, das gleiche sein, tun das nicht):

#include <stdlib.h> 
#include <stdio.h> 

typedef struct { 
    int id; 
    double c[2]; 
    double p[4][2]; 
} Detection; 

int main() 
{ 
    size_t size = sizeof(Detection); 
    printf("sizeof(Detection) = %u\n", size); 
    Detection *detection = malloc(size); 
    detection->id = 0x01020304; 
    *(long long *)(&detection->c[0]) = 0x1011121314151617; 
    *(long long *)(&detection->c[1]) = 0x18191A1B1C1D1E1F; 
    *(long long *)(&detection->p[0][0]) = 0x2021222324252627; 
    *(long long *)(&detection->p[0][1]) = 0x28292A2B2C2D2E2F; 
    *(long long *)(&detection->p[1][0]) = 0x3031323334353637; 
    *(long long *)(&detection->p[1][1]) = 0x38393A3B3C3D3E3F; 

    *(long long *)(&detection->p[2][0]) = 0x4041424344454647; 
    *(long long *)(&detection->p[2][1]) = 0x48494A4B4C4D4E4F; 
    *(long long *)(&detection->p[3][0]) = 0x5051525354555657; 
    *(long long *)(&detection->p[3][1]) = 0x58595A5B5C5D5E5F; 
} 

führen Sie es dann in der Debugger das Speicherlayout, das in meinem Fall zu sehen ist (die 0x01097018 Adresse aus der dritten Zeile beginnend):

0x01097008 01 00 00 00 58 00 00 00 4e 00 00 00 fd fd fd fd ....X...N...ýýýý 
======== detection starts here ========= 
0x01097018 04 03 02 01 cd cd cd cd 17 16 15 14 13 12 11 10 ....ÍÍÍÍ........ 
0x01097028 1f 1e 1d 1c 1b 1a 19 18 27 26 25 24 23 22 21 20 ........'&%$#"! 
0x01097038 2f 2e 2d 2c 2b 2a 29 28 37 36 35 34 33 32 31 30 /.-,+*)(
0x01097048 3f 3e 3d 3c 3b 3a 39 38 47 46 45 44 43 42 41 40 ?>=<;:[email protected] 
0x01097058 4f 4e 4d 4c 4b 4a 49 48 57 56 55 54 53 52 51 50 ONMLKJIHWVUTSRQP 
0x01097068 5f 5e 5d 5c 5b 5a 59 58 

aus den Werten im Speicher können Sie leicht erkennen, wie sich die Struktur im Speicher angelegt, bei kann feststellen, dass Arrays eingebettet sind dieses Speicherlayout.

Als Konsequenz hat free auch absolut keine Ahnung, welche Art von Struktur auf dem anderen Ende des Zeigers sitzt, der an sie übergeben wird. Es erhält einfach eine Adresse, die [angeblich] zuvor von malloc (a void *) zurückgegeben wurde, und weiß, wie man es als Speicherstück freigibt (nicht als Struktur eines bestimmten Typs). Es gibt keine Art von "Zerstörung", außer dass der Speicher als "nicht benutzt" markiert wird.

Ich habe zusätzlich 16 Byte Speicher vor die Adresse durch die malloc zurück zeigen, wie free weiß, wie viele Speicher freizugeben (das ist völlig abhängig von der Implementierung ist, nebenbei bemerkt, und Sie sollten nicht auf sie verlassen in irgendeiner Weise). Sie werden feststellen, dass 58 in der ersten Zeile, die 88 dezimal übersetzt - es ist die Größe des Speichers

zugeordnet

Eine leicht size + 42 zu einem malloc passieren kann, ist es noch richtiges Programm sein würde, es wäre nur die Erinnerung verschwenden.

+0

Beachten Sie, dass gegebener Code wie 'double c [2];' Code wie '* (long long *) (& detection-> c [0]) = 0x1011121314151617;' strenges Aliasing verletzt und nicht definiert ist. –

+0

Sicher, tu das nicht.Ich wollte nur zeigen, dass eine Erinnerung nur eine Erinnerung ist, Bytes ohne Bedeutung. Die Interpretation liegt bei einer Person, die den Code schreibt. – n0rd

1

Wird dies auch kostenlos c und p?

Ja.

Die Arrays c und p sind statisch zugewiesen, was bedeutet, dass die Speicherverwaltung für Sie übernehmen wird; Sie müssen sich keine Sorgen machen.


Daumenregel: Rufen Sie free() so oft wie Sie malloc() genannt.

Hier wird der Speicher einmal dynamisch zugewiesen, daher müssen Sie diesen dynamischen Speicher nur einmal freigeben.

5

Hier gibt es nur eine Zuweisung. Die Felder c und p haben keine separaten Zuweisungen. Die allgemeine Regel ist, dass jeder Anruf zu malloc ausgewogen sein muss, eins zu eins, durch einen Anruf zu free. Der Destruktor wie beschrieben ist alles was benötigt wird. Wenn innerhalb der Struktur andere dynamisch zugewiesene Zeiger vorhanden sind, sind möglicherweise weitere Aufrufe erforderlich, z. B. free.

Beachten Sie, dass die Felder c und p feste Größe haben, die in sizeof(Detection) enthalten ist. In C++ -Feldern können ihre eigenen Konstruktoren haben, die dynamische Zuordnung vornehmen können, aber sie werden normalerweise auch automatisch aus Code zerstört, den der Compiler im Eltern-Destruktor erzeugt.

C hat Arrays variabler Länge (VLAs), die jedoch nicht in einer Struktur, nur in einer Funktionsargumentliste oder in einem Block innerhalb einer Funktion deklariert werden können.

1

Der Speicher für c und p ist inline in der Struktur zugeordnet. Dies liegt daran, c und p als Arrays Arrays und nicht Zeiger. Wenn In C Zeiger und Arrays sind nicht das Gleiche. Wären c und p als Zeiger definiert, müssten Sie dann Speicher zuweisen und freigeben, bevor Sie sie verwenden.

Der Grund für die Verwirrung ist, dass Arrays manchmal in Zeiger zerfallen und umgekehrt. Ein Beispiel hierfür ist die Äquivalenz von double* ptr = c und double* ptr = &c[0] (c ist ein Array). Pointer Decay tritt beim Zugriff auf das Array auf und passiert nicht, wenn wir das Array definieren.

Verwandte Themen