Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - Pointer-Problem / Stack-Überlauf
blaskito - Di 17.11.09 15:17
Titel: Pointer-Problem / Stack-Überlauf
Hallo,
ich habe mir für eine Dateisuche das Konstrukt gebastelt:
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| type TFileFoundType = record Path: Integer; Filename: string[255]; end; TFileFound = array[0..0] of TFileFoundType; |
und natürlich auch eine Variable deklariert:
Delphi-Quelltext
1: 2:
| var pFileFound: ^TFileFound; |
Nun möchte ich Dateien hinzufügen:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| procedure TMF.AddFileArray(Path: Integer; Filename: string); var pTemp:^TFileFound; i,Size:Integer; begin Inc(fFileCount); Size:=SizeOf(pFileFound[0]); GetMem(pTemp,fFileCount*Size); if pFileFound<>nil then begin for i:=1 to fFileCount-1 do pTemp^[i]:=pFileFound[i]; FreeMem(pFileFound); end; pTemp^[fFileCount].Path:=Path; pTemp^[fFileCount].Filename:=Filename; GetMem(pFileFound,fFileCount*Size); for i:=1 to fFileCount do pFileFound^[i]:=pTemp[i]; FreeMem(pTemp); end; |
In der letzten Zeile erhalte ich beim 11. Durchlauf einen Stack-Überlauf. Verdammte Axt: ich finde den Fehler nicht! Was mache ich falsch? Ich muss gestehen, dass Pointer und dynamische Arrays nicht mein tägliches Brot sind. Also bitte Nachsicht für Blödmannsfehler.
Gruß aus dem Norden
blaskito
HelgeLange - Di 17.11.09 16:35
ich sehe keinen grund, warum Du das hin und her kopieren musst, wenn DU mit dynamischen arrays arbeitest.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
| type TFileFoundType = record Path: Integer; Filename: string[255]; end; TFileFound = array of TFileFoundType;
var pFileFound: ^TFileFound;
procedure TMF.AddFileArray(Path: Integer; Filename: string); begin if pFileFound = nil then fFileCount := 0;
Inc(fFileCount); SetLength(pFileFound, fFileCount);
pFileFound^[fFileCount-1].Path:=Path; pFileFound^[fFileCount-1].Filename:=Filename; end; |
habs ned gestestet, sollte aber so gehen
blaskito - Di 17.11.09 16:59
Hallo,
danke für den Tip. Leider bekomme ich jetzt zum SetLength die Meldung "Inkompatible Typen". Das könnte vielleicht daran liegen, das pFileFound ja nicht das dynamische Array sondern der Pointer darauf ist. Das Hin- und Herkopieren habe ich so aus einigen Artikeln herausgelesen. Damit sollte vermieden werden, dass durch ein weiteres GetMem ein Datenverlust in dem Produktivarray eintritt. Das habe ich einfach mal so als Fakt hingenommen.
Gibt es irgendwo ein Tutorial zum Thema dyn Arrays?
Gruß aus dem Norden
blaskito
Flamefire - Di 17.11.09 17:48
dein fehler ist leicht zu beheben:
Delphi-Quelltext
1:
| for i:=1 to fFileCount do pFileFound^[i]:=pTemp^[i]; |
und mit dem dynamischen array ist es klar:
du musst natürlich die pointerdeklaration wegnehmen:
Delphi-Quelltext
1:
| pFileFound: TFileFound; |
zur erklärung: mit getmem holst du dir zusammenhängenden speicher.
stell dir einfach vor, du hast nen datenblock, in dem deine aktuellen daten stehen.
wenn du also mehr brauchst, muss der datenblock größer werden.
also: alten block sichern, datenblock freigeben und größeren holen, alte daten wiederherstellen, neue daten einfügen
stimmt also
bei dyn arrays setzt du die länge erst zur laufzeit. und intern macht delphi genau das oben beschriebene.
aber kurz:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| SetLength(MyArray,0); SetLength(MyArray,Length(MyArray)+1); MyArray[High(MyArray)]:=...SetLength(MyArray,0); |
ansonsten wäre für dieses thema entweder ein buffer besser (einfach gesagt, ein array mit unterschiedlichen werten für anzahl der einträge und maximaler eintragsgröße; das spart das ständige vergrößern und somit umkopieren-->schneller)
oder eine verkettete liste (gar kein umkopieren)
blaskito - Di 17.11.09 22:13
Hallo Flamefire,
was ich schon sagte: natürlich ein Blödmannsfehler!
Da ich nicht weiß, wie viele Dateien mich erwarten (es dürften bei fast 30.000 Ordnern sehr viele Dateien werden) macht ein Buffer keinen Sinn. Aber die einfach verkettete Liste natürlich. Denn der Zeitaufwand beim Umkopieren wird wahrscheinlich bei einer großen Anzahl Einträgen ein spürbarer Faktor werden.
Vielen Dank
blaskito
Flamefire - Mi 18.11.09 00:04
ich glaube du hast den buffer falsch verstanden.
im prinzip sieht er so aus:
Delphi-Quelltext
1: 2: 3: 4:
| TBuffer=record size,count=Integer; Elems=Array of xxx; end; |
jetzt initialisierst du den z.b. mit:
Delphi-Quelltext
1: 2: 3:
| buffer.size:=128; SetLength(buffer.Elems,buffer.size); buffer.count:=0; |
und einfügen geht dann so:
Delphi-Quelltext
1: 2: 3: 4: 5:
| if(buffer.count>=buffer.size) then begin buffer.size:=buffer.size*2; SetLength(buffer.Elems,buffer.size); end; buffer.Elems[buffer.count]:=zzz; |
verschiedene Delphi klassen machen das auch so (bzw ähnlich)
-->s. Capacity eigenschaft
blaskito - Fr 20.11.09 08:50
Ah ja,
ich glaube, jetzt habbichs. So erzeuge ich immer zusammenhängende Blöcke. Damit fragmentiere ich das RAM natürlich nicht so stark wie mit einer sich dynamisch bei jedem Eintrag verlängernde Liste. Das war mir bislang völlig unbekannt. Ich werd's mal testen.
Schönen Dank
blaskito
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!