Ich habe aktuell Probleme mit Pointern und offenen Arrays.
Irgendwie kapiere ich nicht, warum das erste Beispiel nicht läuft und das zweite läuft. Ich dereferenziere wieder auf PBuffer zu TBuffer und das ist doch ein offenes Array. WO habe ich da das Denkproblem ?
procedure TForm1.ButtonClick(Sender: TObject);
Type
TBuffer= Array of Byte;
PTBuffer= ^TBuffer;
var
PBuffer: PTBuffer;
BufLen: LongInt;
begin
PBuffer:= nil;
BufLen:= 100;
SetLength((PBuffer^),BufLen);
try
TBuffer(PBuffer^)[1] := 98; // Hier bekomme ich eine Speicherverletzung
finally
SetLength((PBuffer^),0);
end;
end;
af0815 hat geschrieben:Ich habe aktuell Probleme mit Pointern und offenen Arrays.
Irgendwie kapiere ich nicht, warum das erste Beispiel nicht läuft und das zweite läuft. Ich dereferenziere wieder auf PBuffer zu TBuffer und das ist doch ein offenes Array. WO habe ich da das Denkproblem ?
Pointers nach automatische Typen sind komplex. Der Fehler ist das nirgendwo Speicher alloziert wird fuer ein TBuffer. Ja, der TBuffer wird dimensioniert, aber kein Speicher für die Basisstruktur der TBuffer.
Vielleicht würde ein new (PTBuffer) statt pbuffer:=nil funktionieren.
Type
TBuffer= Array of Byte;
PTBuffer= ^TBuffer;
var
PBuffer: PTBuffer;
BufLen: LongInt;
buffer: tbuffer;
begin
PBuffer:= nil;
BufLen:= 100;
pbuffer:= @buffer;
SetLength((PBuffer^),BufLen);
try
TBuffer(PBuffer^)[1] := 98;
finally
SetLength((PBuffer^),0);
end;
end;
PTBuffer ist ja ein Pointer auf den Datenpointer des Dynamischen Arrays. Oder wie Marco schreibt, den Pointer auf Pointer mit New() initialisieren welches PTBuffer^ auf nil initialisieren muss, sonst funktioniert setlength() nicht. Die Freigabe geschieht mit Dispose(), Freemem() führt zu memory leak, da der Speicher des dynamischen Arrays nicht freigegeben wird.
Zuletzt geändert von mse am Mo 27. Feb 2017, 15:59, insgesamt 1-mal geändert.
Irgendwie kapiere ich nicht, warum das erste Beispiel nicht läuft und das zweite läuft. Ich dereferenziere wieder auf PBuffer zu TBuffer und das ist doch ein offenes Array. WO habe ich da das Denkproblem ?
PBuffer ist bei die ein Pointer der bei die auf die Array zeigen soll, aber du hast den Speicher dafür nicht reserviert. Ich meine damit den Speicher auf die Array selbst , und nicht den welcher mit SetLength reserviert wird.
Die Typenumwandlung kannst dir auch sparen.
procedure TForm1.Button1Click(Sender: TObject);
Type
TBuffer= Array of Byte;
PBuffer= ^TBuffer;
var
Buffer: PBuffer;
BufLen: LongInt;
begin
BufLen:= 100;
New(Buffer); // Dies wurde vergessen
SetLength(Buffer^,BufLen);
try
Buffer^[1] := 98; // Hier bekomme ich eine Speicherverletzung
ShowMessage(IntToStr(Buffer^[1]));
finally
SetLength((Buffer^),0);
Dispose(Buffer);
end;
end;
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot
Zusatzfrage: Ist TByteArray = TArray<Byte> und TByteArray = Array of Byte gleich, auch in Hinsicht der Pointer ? Und in welchen Modus funktionieren die Generics eigentlich ?
Kann ich das mit den Pointern irgendwo nachlesen. Ich habe bisher nur Teilbereiche gefunden aber nicht wirklich die Übersicht bekommen. Auch lese ich das geht nur im Delphimodus - sorry - aber ich habe bisher noch nicht gefunden wo WIRKLICH die Unterschiede sind. Bis jetzt bin ich davon ausgegangen, das der Delphimodus nur eine Syntax'wichere' Geschichte ist und das alles etwas strenger im fpc modus und H+ ist. In den Compilermodes http://www.freepascal.org/docs-html/pro ... gse75.html sieht das ja nicht soooo unterschiedlich aus.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).
mse hat geschrieben:Von generics lasse ich die Finger...
Glaube mir, das ist nicht freiwillig. Sondern ich möchte eine Bibliothek von Delphi Berlin nach Lazarus portieren, nur das ist gespickt voll mit Generics. Also muss ich mich mit Generics auseinandersetzen und verstehen wie die funktionieren.
Vor allen, da ich derzeit aus der Bibliothek eine dll unter Delphi gemacht habe und eine Hauptfunktion nur verwende. Dort bin ich auf die verschiedensten Probleme mit den Pointern gestoßen. Zuletzt hab ich mich damit abgemüht, das ich einen String von Delphi wieder zurück in Lazarus bringe. Da bin ich darauf gestoßen, das Delphi ja standardmäßig UTF16 verwendet. Na klar das ich den nicht direkt in einen UTF8 bringe und nur immer das erste Zeichen sehe.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).
marcov hat geschrieben:Ah, aber ich alloziere keine TBuffer aber ein PTBuffer. Und PTBuffer ist nur ein pointer nach ein TBuffer, also ein platz.
Im falle deines offenen Array ist das richtig, es wird nur Platz für den Zeiger reserviert mit dem SetLength dann weiter arbeiten kann. Aber nochmal, sobald die Größe eines Datenobjekts bekannt ist, wird auch Speicher für die Daten reserviert.
mse hat geschrieben:Wird "Finalize(P^)" nicht von dispose() ausgeführt und ist daher unnötig?
Wenn man bedenkt, dass New und Dispose von den Borländern damals für Turbo Vision entwickelt wurde ist das eine gute frage, da gab es das Finalize meines Wissens noch nicht (sicher bin ich aber nicht).
Wird "Finalize(P^)" nicht von dispose() ausgeführt und ist daher unnötig?
Ich denke das es tatsächlich nicht noetig ist mit new und dispose separate zu init/finalizen. Ich hatte es schnell kopiert von ein getmem/freemem array beispiel.
marcov hat geschrieben:...Ich hatte es schnell kopiert von ein getmem/freemem array beispiel.
Ich versteh jetzt nicht genau was du damit meinst, willst du dein Zeiger Problem jetzt mit GetMem/FreeMem lösen? Das würde ich mir gut überlegen, denn GetMem () Alloziert "nur" Speicherplatz, bei Änderung einer Array Größe geht nicht nur der alte Inhalt verloren, sondern der alte Speicherplatz endet als Speicherfraß. Mit SetLength hingegen passiert das nicht, der alte Inhalt bleibt erhalten.
type
PA = ^TA;
TA = array [0..$FFFF] of byte;
procedure TForm1.Button1Click(Sender: TObject);
var
a: pa;
i: integer;
begin
Getmem(a, 20);
for i := 0 to 19 do begin
a^[i] := i;
end;
for i := 0 to 19 do begin
WriteLn(a^[i]);
end;
Freemem(a, 20);
end;
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot