Das Ganze kann grösser sein als die Summe seiner Teile (Quantenmechanik in C
).
Es liegt daran, wie Datenstrukturen auf der jeweiligen Plattform verwaltet werden. Normalerweise werden die primitiven Datentypen hintereinander "aligned" abgelegt, also immer an 64Bit Grenzen.
Ein Pointer braucht 64Bit (also 8 Byte) weil der Adressraum so gross ist, ein unsigned char (UC) nur ein Byte. Aber eine struct aus einem Pointer und einem UC hat als sizeof trotzdem 2*8Byte, da auch der UC in einem 64Bit Block verwaltet wird. Eine struct aus einem Pointer und zwei UC wäre auch 16Byte gross, da beide UC in den 64Bit Block passen. Definierst Du die struct anders (ein UC, ein Pointer, ein UC) braucht sie plötzlich 3*8Byte.
Ändern könnte man das durch ein Compiler-Direktive namens "#pragma pack", dann würde die letzte struct nur noch 10 Byte gross sein - aber man muss mit Performanceverringerung rechnen.
Letztlich ist die struct also "mindestens" so gross, wie die Summe ihrer Member.
Nur um das nochmal nachzuvollziehen - auch die simple Reihenfolge in welcher die Member in einem Struct definiert werden kann den Speicherverbrauch über das Minimum heraus erhöhen und gibt gleichzeitig den Speicheraufbau vor?
Dann gehe ich nochmal über die Anordnung der Structs, wäre dann ja logisch die Pointer ans Ende zu legen und statische Member vorne in der Definition abzulegen damit keine Fragmentierung entsteht und Daten unsinnig verschoben werden müssen(?)
Gerne, aber was genau ist denn darin nicht nachvollziehbar?
Das macht die Funktion strdup - ein char Array ist null-terminiert, d.h. das letzte Byte ist 0x00 (und das ist auch das einzige Byte im Array, dass diesen Wert haben kann). So kann die Länge des Arrays bestimmt werden, indem man alle Bytes vom Anfang bis zum ersten 0x00 zählt. Das macht z.B. die Funktion strlen(). Beim Übergeben im Beispiel von "Joe Alex" wird also ein Pointer auf den Anfang dieses Arrays (liegt als Konstante im Programmcode) übergeben (also auf die Adresse des Buchstabens J). Die Konstante ist tatsächlich 9 Bytes lang und das letzte Byte (hinter x) ist 0x00. strdup zählt die Bytes bis zur 0x00, allokiert dann 9 Byte Speicher, kopiert diese 9 Byte ("Joe Alex" + 0x00) und gibt den Pointer darauf zurück - was dann unter dem Pointer name gespeichert wird.
Deswegen wird das in der destroy Funktion ja auch wieder freigegeben.
Um das nochmal in eigene Worte zu kleiden was du gerade geschrieben hast. Wenn der Pointer anglegt wird, enthält er keine Daten so fern nicht initilaisiert.
strdup aber allokiert dann den Speicher und orientiert sich an "\0" Ende des char Arrays um die Anzahl festzustellen. Mit free(pointer) wird dann der Speicher wieder freigeben. Verstehe ich - danke für die Klärung.
Meine vorherigen Frage hatte Brother John geklärt - mir war nicht bewusst das man Speicher für das struct erfragen muß + Extra Speicher für die Pointer(inhalte).
Irgendwie war ich vorher auf dem falschen Dampfer das ich doch einfach nur
sizeof(struct name) schreiben kann, was "automatisch" bestimmt wie groß.... aber war halt nicht gerade genug gedacht.
------------------
Ich hab gestern schon mal zwischendurch gefragt, aber... :
Ich sitze nun an einem Memory Leak bzw. wird ein einmalig falsche Read (laut Valgrind/Valkyrie) ausgeführt den ich bisher nicht beheben konnte, aber genau die Problemstelle im Code kenne ich die diesen Read ausführt - weiß aber nicht warum der Fehler nur einmal auftritt und danach scheinbar reibungslos funktioniert.
Vielleicht mag sich da jemand mal die Mühe machen in den Code zu schauen?
Ich habe das Projekt auch auf Github hochgeladen, mit Source und Makefile.
Zu finden unter:
https://github.com/jrie/relayx-sdl
Das Projekt kann mit g++ und "make all" kompiliert werden, SDL 2.0.4 (latest development build) ist allerdings erforderlich.
Der Fehler passiert in Zeile:
360 bis 374, konkret der "memmove" in Zeile 363.
Um die Funktion zu triggern die für das Ungrouping zuständing ist und leere Gruppen überschreiben sollen mit oberen memmove, geht man wie folgt vor.
Mit gedrückter linker Maustaste eine Auswahl ziehen um einen Container anzulegen. Das wiederholen, bis man insgesamt vier Container erstellt hat.
Dann einen Container markieren und mit Strg (halten) + Klick auf einen anderen gruppieren.
Dann den dritten freien auswählen und mit dem vierten Container gruppieren.
Nun klickt man mit Links auf einen der ersten beiden gruppierten Container und hält Strg und klickt nochmals auf diesen.
Der Container wird dann aus der Gruppe gelöscht, und da die Gruppe nur 2 Container hat wird diese auch gelöscht.
Jetzt wurde der Fehler (memmove) schon getriggert. Ein "invalid read von 8 Bytes" (64 bit) im Valkyrie Statusfenster.
Wiederholt man das ganze, Gruppe anlegen, vorherigen Gruppe an Stelle 0 löschen, tritt der Fehler nicht mehr auf.
Kein Invalid Read oder Write zu sehen.
Vielleicht liegt der Fehler auch nur dabei, wie der Speicher berechnet wird (gespeichert in
bytesToMove), aber bei darauffolgenden auflösen der ersten Gruppe in der Reihenfolge kommt kein Fehler mehr.