realloc zerhackt Werte
-
Hallo,
irgendwie werden mir bei der Benutzung von realloc Werte zerhackt - das komische daran: Auf Mac OS funktioniert es, auf Linux nicht.
Ich mal der abgespeckte Code:
Modul A:
struct array { size_t memsize; // Größe des reservierten Speichers auf den men zeigt size_t itemsize; // Die Größe eines Array-Elements unsigned long itemcount; // Die Anzahl der sich im Array befindendenen Elemente void *mem; // Zeiger auf den für die Arrayitems reservierten Speicher (==erstes freies Byte hinter Struktur) int test; }; struct array *addArrayItem(struct array *a, void *item) { if(a->memsize - a->itemcount*a->itemsize < a->itemsize) { // nicht mehr genügend Platz für neues Item // Speicher wird erweitert size_t new_size = a->memsize+(size_t)(a->itemsize*ADD); a = (struct array *)realloc(a, new_size); if(a == NULL) return NULL; a->memsize = new_size; a->mem = a + 1; } // ... ab hier ist Speicher auf jeden Fall groß genug } // Element anhängen; Adresse zum Anhängen: Adresse von Array + Itemanzahl*Itemgröße void * ptr = memcpy(a->mem + a->itemsize*a->itemcount, item, a->itemsize); if(ptr==NULL) return NULL; (a->itemcount)++; // Itemanzahl erhöhen return a; }
Modul B:
/* Vorher wurde ein Array mit Array a1: memsize: 20 itemsize: 4 itemcount: 0 *mem: 0x793078 test: -1 initialisiert, d.h. ohne Speichererweiterung können 5 int-Elemente gespeichert werden */ int eins = 1; int zwei = 2; int drei = 3; int vier = 4; int fuenf = 5; int sechs = 6; a1 = addArrayItem(a1, &eins); a1 = addArrayItem(a1, &zwei); a1 = addArrayItem(a1, &drei); a1 = addArrayItem(a1, &vier); a1 = addArrayItem(a1, &fuenf); //a1 = addArrayItem(a1, &sechs); for(int i = 0; i<a1->itemcount; i++) { printf("Element %i: %i\n", i, *((int *) a1->mem+i) ); }
Ohne die auskommentierten addArrayItem-Aufrufe ist die Ausgabe so wie sie sein soll:
Element 0: 1 Element 1: 2 Element 2: 3 Element 3: 4 Element 4: 5
Mit den zusätzlichen addArrayItem-Aufrufe (d.h. realloc wird angewandt) werden jedoch eben die ersten paar Elemente falsch ausgeben.
Element 0: 33 Element 1: 0 Element 2: 7942176 Element 3: 0 Element 4: 5 Element 5: 6
... allerdings nur auf Linux, bei meinem Mac wird alles richtig ausgegeben.
Ich bin sowas von überfragt....
Wäre echt dankbar wenn mir da einer weiterhelfen könnte !
Grüße,
wertixx
-
Du brauchst den Inhalt des alten Speicherbereichs nicht selbst in den neuen zu kopieren. Das macht realloc() automatisch.
Der alte Speicherbereichs wird von realloc() freigegeben, dh du solltest auf ihn auch nicht mehr zugreifen. Sein Inhalt kann vom Betriebsystem geändert werden oder sogar völlig freigegeben werden, so daß ein Zugriff zu einem Speicherfehler führt.
Die Zeile
a->mem = a + 1;
solltest du zu
a->mem = a;
ändern.
-
denk der fehler beginnt wenn dann schon hier:
a = (struct array *)realloc(a, new_size);
-
Stimmt, da steckt auch noch der Wurm drin. Es muß
a->mem = (struct array *)realloc(a->mem, new_size);
heißen.
a->mem=a+1
muß dann ganz weg usw.
-
Hmm, sry, das hätte ich noch anmerken sollen: a->mem zeigt auf das erste frei Byte HINTER der Array-Struktur im Speicher.
D.h. das Array wird an der Adresse von a abgespeichert, die Items an der Adresse a + 1 (Zeigerarithmetik...).
Von daher muss ich a->mem neu setzen.
(Ich hab die Ändern auch ausprobiert, das führt zum totalen Speichercrash des Programms)
-
Leicht vereinfacht sieht eine korrigierte Fassung z.B. so aus:
typedef struct { size_t memsize; // Größe des reservierten Speichers auf den men zeigt size_t itemsize; // Die Größe eines Array-Elements unsigned long itemcount;// Die Anzahl der sich im Array befindendenen Elemente void *mem; // Zeiger auf den für das Array reservierten Speicher int test; } Array; Array *addArrayItem(Array *a, void *item) { if( a->memsize < (a->itemcount+1)*a->itemsize) { // nicht mehr genügend Platz für neues Item a->mem = realloc( a->mem, (a->itemcount+1)*a->itemsize ); if( !a->mem ) return 0; } // Element anhängen; Adresse zum Anhängen: Adresse von Array + Itemanzahl*Itemgröße memcpy(a->mem + a->itemsize*a->itemcount, item, a->itemsize); a->itemcount++; // Itemanzahl erhöhen return a; }
-
Wie gesagt, dass führt leider zum invalid pointer Fehlermeldungen.
a->mem wurde ja vorher nicht mit malloc() Speicher zugewiesen. Das Array wurde so initialisiert:
struct array *a1 = (struct array *)malloc(sizeof(struct array) + 20); a1->itemsize = (size_t)4; a1->memsize = (size_t)20; a1->itemcount = (unsigned long)0; a1->test = -1;
Nochmal zur Erklärung:
Ich will im Speicher eine Array-Struktur ablegen. Hinter der Array-Struktur sollen die Array-Items folgen.
-
Wenn du das Folgende verwendest
struct array *a1 = (struct array *)calloc(1,sizeof*a1); a1->itemsize = 4; a1->test = -1;
steht erstmal alles mem-Relevante auf 0/NULL und das erste realloc schlägt auch nicht mehr fehl.
-
Hm, aber ich versteh einfach nicht warum realloc in meinem Code die ersten paar (aber nicht alle) Werte zerhackt (und auch nur auf linux...)
calloc beim initialisieren hilft auch nichts
-
Du hast nicht viel verstanden.
calloc initialisiert immer, malloc nie, egal was du vermutest.
Führe den Beispielcode im Debugger aus und du lernst.
Gehe davon aus, dass realloc genauso arbeitet wie spezifiziert und wenn etwas nicht deinen Erwartungen entspricht, liegt es immer an dir und deinem Code ("der Compiler hat immer Recht").
-
Konfusius schrieb:
Stimmt, da steckt auch noch der Wurm drin. Es muß
a->mem = (struct array *)realloc(a->mem, new_size);
heißen.
sry. aber wenn ich meine doku richtig gelesen hab ist das immernoch falsch
-
Hallo,
Warum ist dir das so wichtig, dass das Array direkt hinter der Struktur liegt? Weil dadurch musst du umständlich mit Zeigern hantieren...
Die Lösung von Wutz finde ich wesentlich übersichtlicher und intuitiver :).
-
Hi nochmal,
mir ist es so wichtig, da es meine Vorgaben so verlangen
Es ist mir schon klar, dass malloc nicht initialisiert. ICH initialisiere den mit malloc reservierten Speicherbereich aber (wie angegeben). Und genau die Initialisierungen zerhackt mir realloc zumindest partiell und ich verstehe nicht warum. Eine Antwort darauf hab ich bisher auch nicht herauslesen können.
Und der Vorschlag mit calloc hat außer weiteren Fehlermeldungen nichts gebracht. Von daher habe ich daraus auch nichts lernen können.
Achja, [unregistrierter Benutzer] war nicht ich
-
Du holst beim realloc nur Speicher für das (vergrößerte) Array, nicht für die Struktur selbst.
-
Also werden die alten Initialisierungen doch nicht mitkopiert?
Aber es hieß doch:
Du brauchst den Inhalt des alten Speicherbereichs nicht selbst in den neuen zu kopieren. Das macht realloc() automatisch.
-
wertixx schrieb:
Also werden die alten Initialisierungen doch nicht mitkopiert?
Es geht nicht um's kopieren. Du holst einfach nicht genug Speicher.
Du holst mit realloc new_size Bytes für Struktur und Array, tust aber im weiteren Verlauf so, als wären new_size Bytes für das Array allein da.
-
Oh man, jetzt hat es klick gemacht
Ich hab bei newSize vergessen, den Speicherplatz für die Struktur mit einzuberechnen.
Es hätte
size_t new_size = sizeof(struct array *) + a->memsize + (size_t)(a->itemsize*ADD);
lauten müssen. Da war ich echt ne Blindschleiche...
Danke für die vielen antworten