Hallo, ich möchte aus einem buffer dessen inhalt 99k groß ist eine verkettete liste erstellen. Je nach inhalt des buffers werden listenelemente neu erstellt und an die liste angefügt - d.h. mit realloc() wird der speicher der liste erweitert und an die entsprechende stelle wird das neue element angefüt. das ganze funktioniert auch super bis zu einer größe von ca. 40k. Habe ich mehr daten - so bekomme ich einen heap-fehler - (in dbgheap.c linie 1692) - ich programmiere in C in VisualStudio! Leider bringt mir die abfrage ob mein Retrunpointer der realloc-funktion NULL ist auch nichts - da er einfach "leer" - d.h. ich kann nicht darauf zugreifen... Hat jemand zumindest einen Ansatz woran das liegen könnte?? Danke
Was heißt max .. schrieb: > mit realloc() wird der > speicher der liste erweitert und an die entsprechende stelle wird das > neue element angefüt. Das ist doch dann keine verkettete Liste. Der Witz an dadran ist doch, dass man ohne viel Neuallokieren die Liste erweitern kann. Du erstellst dir am besten eine Struktur, in der du die Daten ablegst und einen Zeiger auf ein weiteres Element der Struktur.
es geht nicht um die liste... vereinfacht gesagt - ich möchte einfach NUR speicher erweitern - mit realloc - ab einer bestimmten größe geht das nicht mehr und ich bekomme keinen nullpointer zurück - sondern einen heap-error vom visualstudio.
max .. schrieb: > vereinfacht gesagt - ich möchte einfach NUR speicher erweitern - mit > realloc - ab einer bestimmten größe geht das nicht mehr und ich bekomme > keinen nullpointer zurück - sondern einen heap-error vom visualstudio. dann ist der fehler aber woanders, du überschreibst vermutlich irgendwo die HEAP-Struktur. Beim nächsten realloc kommt dann dieser Fehler.
was heißt das konkret "heap-struktur" überschreiben??
max .. schrieb: > was heißt das konkret "heap-struktur" überschreiben?? du schreibst etwas in einen speicher Bereich der dich nichts angeht. z.b.:
1 | int x[5]; |
2 | x[12] = 12; |
wie kommt es dazu?? und wie kann ich das verhindern??
max .. schrieb: > ich möchte aus einem buffer dessen inhalt 99k groß ist eine verkettete > liste erstellen. Je nach inhalt des buffers werden listenelemente neu > erstellt und an die liste angefügt - d.h. mit realloc() wird der > speicher der liste erweitert und an die entsprechende stelle wird das > neue element angefüt. Sprichst Du hier von einem Array oder einer Liste? Wenn Du in diesem Speicherbereich eine echte Liste speicherst - also mit Pointern auf z.B. vorhergehendes oder folgendes Element in den jeweiligen Listenelementen - dann kriegst Du ein Problem, wenn das realloc den Speicherbereich durch die Gegend schiebt, weil dann die ganzen Pointer in der Liste nicht mehr stimmen. Wenn Du allerdings nur auf ein Array zugreifst - also Pointer auf den Speicherbereich plus index - dann sollte das eigentlich gehen. Viele Grüße, Simon
max .. schrieb: > wie kommt es dazu?? > und wie kann ich das verhindern?? java verwenden. In C muss man halt wissen was man macht, es gibt keine Möglichkeit es zu verhindern. Ich glaube es wird langsam zeit das du uns etwas quellcode zeigst. Deine Beschreibung klingt zumindest sehr nach "denn sie wissen nicht was sie tun"
es handelt sich um ein array! /* Childnode-Array um 1 vergroessern : */ aktunode->childnodes = (NODE **) realloc(aktunode->childnodes,sizeof(NODEPTR)*(aktunode->index+1));
max .. schrieb: > es handelt sich um ein array! > > /* Childnode-Array um 1 vergroessern : */ > aktunode->childnodes = (NODE **) > realloc(aktunode->childnodes,sizeof(NODEPTR)*(aktunode->index+1)); der Fehler liegt in dem Teil welchen du uns nicht zeigst.
du meinst in der node-struktur!? der code wäre etwas lang um ihn hier zu posten... das ist mein struktur - welche an der stelle childnodes immer erweitern wird. Programmablauf ist so: Buffer durchsuchen - wenn alle infos gefunden - struktur um ein element erweitern und infos reinschreiben...mehr passiert da nicht. typedef struct nodestruct { char info[ INFO_SIZE]; char name[ NAME_SIZE]; char wert[ WERT_SIZE]; struct nodestruct *parentnode; struct nodestruct **childnodes; // Array of nodes int childcount; int nodelevel; } NODE; typedef NODE *NODEPTR;
max .. schrieb: > das ist mein struktur - welche an der stelle childnodes immer erweitern > wird. > > Programmablauf ist so: > Buffer durchsuchen - wenn alle infos gefunden - struktur um ein element > erweitern und infos reinschreiben...mehr passiert da nicht. > > typedef struct nodestruct > { [...] > struct nodestruct *parentnode; > struct nodestruct **childnodes; // Array of nodes [...] > } > NODE; Da sind doch deine Pointer. Können die childnodes selber wieder der parent-nodes für andere sein? Falls ja, hast Du ein Problem, dann musst Du nämlich bei einem realloc alle *parentnodes ändern, die in dein reallokiertes Array zeigen. Realloc kann den Speicherbereich verschieben, damit werden Pointer die da reinzeigen potentiell ungültig (!). Meine Empfehlung: Allokiere alle nodes einzeln und ersetze das childnode-Array z.B. durch einen next-sibling-Pointer, verwende also eine klassische linere Liste statt dem Array. Dann ändern sich die Adressen der Nodes nicht. Viele Grüße, Simon
ja genau so ist es - die die childs können auch parents sein! guter hinweis - dem werde ich mal nachgehen!! aber warum funktioniert das ganze dann nur für eine bestimmte anzahl an nodes - wenn ich diese anzahl überschreite (also mehr als 40k habe) gehts nicht mehr?! das ist also kein prinzipielles problem..?!?!
max .. schrieb: > aber warum funktioniert das ganze dann nur für eine bestimmte anzahl an > nodes - wenn ich diese anzahl überschreite (also mehr als 40k habe) > gehts nicht mehr?! das ist also kein prinzipielles problem..?!?! Die libc (malloc/calloc/realloc) allokiert den Speicher beim Betriebssystem üblicherweise in größeren Blöcken. Diese Blöcke werden dann libc-intern bei einem *alloc aufgeteilt und verwaltet. Das wird so gemacht, weil Programme gerne sehr kleine Häppchen haben wollen, das "echte" allokieren beim Betriebssystem aber eine teure Operation ist. Bei Deinem realloc ist es also am Anfang wahrscheinlich, dass der Speicher noch nicht verschoben wird, weil hinter dem Block noch von der libc allokierter Speicher bereitsteht. Irgendwann aber ist dieser "reserve-Platz" aufgebraucht und die libc muss neuen Speicher beim Betriebssystem anfragen oder in ihren anderen reservierten Blöcken nach freiem zusammenhängendem Speicher für das wachsende Array suchen. Dann ändern sich die Pointer und es knallt. Viele Grüße, Simon
ja das klingt logisch! auf dieser fährte war ich auch schon...man kann im visual studio auch einen reservespeicher einstellen. das problem sollte man ja aber im programm lösen! Aber soweit so gut - mit deinen inofs kann ich gut was anfangen!! Danke.
Das hängt davon ab, wieviel Platz hinter Deinem ursprünglichen Array noch frei ist. Z.B. es sind 40k zusammenhängender Speichr frei. Jetzt allokierst Du ein Array mit 20k und erweiterst es anschließend auf 40k, dann wird das Array einfach nur vergrößert, die alten Daten bleiben an der gleichen Stelle im Speicher wie vorher. Erweitest Du das Array aber auf z.B. 60k allokiert die Speicherverwaltung einen komplett neuen Block kopiert die alten Daten da rein und gibt den alten Block frei. Im ersten Fall ist der Pointer nach dem realloc der selbe, im zweiten Fall nicht.
der speicherbedarf wächst ja an - sagen wir ich reallokiere immer um 10k pro aufruf! irgendwann reicht der speicher nicht mehr - kann ich diesen "zeitpunkt" abfragen??
Simon Budig schrieb: > "reserve-Platz" Der ist eigentlich nicht reserviert, sondern nur noch nicht anderweitig vergeben. Das Ganze häng auch stark von der Reihenfolge der Aufrufe ab. Allokiert man z.B. zwei Arrays und vergrößert dann das erste, führt das fast immer zu einer Verschiebung im Speicher. Gibt man das zweite Array vor dem realoc des ersten wieder frei, dann meist nicht.
max .. schrieb: > der speicherbedarf wächst ja an - sagen wir ich reallokiere immer um 10k > pro aufruf! irgendwann reicht der speicher nicht mehr - kann ich diesen > "zeitpunkt" abfragen?? Eher nicht, das hängt wie gesagt auch davion ab was da sonst noch so im Speicher passiert und Du müßtest an die internen Listen der Speicherverwaltung rankommen. Machbar ist das, aber das willst Du nicht wirklich tun. Du kannst höchsten feststellen, das es passiert ist in dem Du den Pointer vor dem realloc mit dem Pointer nach dem realloc vergleichst.
dann könnte ich den pointer doch auch mit NULL vergleichen??? aber genau das geht ja nicht - weil der pointer welcher auf den neuen bereich zeigt - "leer" ist (also auch nicht NULL).
Ein Rückgabewert von realloc() ist entweder NULL oder nicht NULL. Ein "leer" habe ich noch nicht gesehen.
Klaus Wachtler schrieb: > Ein Rückgabewert von realloc() ist entweder NULL oder nicht NULL. > Ein "leer" habe ich noch nicht gesehen. es gibt ja noch nullptr g
Das wogt ja hin und her hier. Wie waers hiermit: Du machst keine realloc bei jedem neuen Element, sondern Du allozierst 10 oder 100 oder 1000 neue Elemente. Spart ne Menge Zeit, und Du fragmentierst Deinen Speicher nicht so doll. Immerhin reallozierst Du den Speicherbereich jedesmal um 4 Bytes, das lohnt nicht wirklich zu sparen. Vielleicht verscheindet dann auch der Fehler.
max .. schrieb: > dann könnte ich den pointer doch auch mit NULL vergleichen??? > aber genau das geht ja nicht - weil der pointer welcher auf den neuen > bereich zeigt - "leer" ist (also auch nicht NULL). Mit NULL vergleichen solltest Du sowieso. Wenn realloc NULL zurückliefert, hast Du gar keinen freien Speicher mehr. Ich meinte eher sowas:
1 | NODE **tP = aktunode->childnodes; |
2 | aktunode->childnodes = (NODE **)realloc(aktunode->childnodes,sizeof(NODEPTR)*(aktunode->index+1)); |
3 | if(aktunode->childnodes) { |
4 | if(aktunode->childnodes == tP) { |
5 | // memory not moved, all pointers into old block are still valid
|
6 | } else { |
7 | // memory moved, all pointers into old block are now invalid !
|
8 | }
|
9 | } else { |
10 | // error, no more memory
|
11 | free(tP); |
12 | }
|
wie schon erwähnt ist das Problem, dass realloc nicht garantiert, dass der ursprüngliche Pointer gültig bleibt. Der Rückgabewert enthält den neuen Pointer auf den Speicher. Der Inhalt wurde vorher kopiert. Das hat zwei Konsequenzen: alle Pointer auf die ursprüngliche Struktur sind ungültig und müssen ersetzt werden. Alle Pointer untereinander in deiner Linked-List sind kaputt.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.