Pointer und Arrays

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6200
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Pointer und Arrays

Beitrag von af0815 »

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 ?

Code: Alles auswählen

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;
 


Das geht

Code: Alles auswählen

procedure TForm1.Button4Click(Sender: TObject);
Type
  TBuffer= Array of Byte;
  PTBuffer= ^TBuffer;
var
  Buffer: TBuffer;
  BufLen: LongInt;
begin
  Buffer:= nil;
  BufLen:= 100;
  SetLength((Buffer),BufLen);
  try
    TBuffer(Buffer)[1] := 98;
  finally
    SetLength((Buffer),0);
  end;
end;
 
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

marcov
Beiträge: 1100
Registriert: Di 5. Aug 2008, 09:37
OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk)
CPU-Target: 32/64,PPC(+64), ARM
Wohnort: Eindhoven (Niederlande)

Re: Pointer und Arrays

Beitrag von marcov »

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.

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: Pointer und Arrays

Beitrag von mse »

[quote="af0815"]

Code: Alles auswählen

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); <<<<<<<---------
 

Die Speicherverletzung sollte hier kommen, da PBuffer nil ist und PBuffer^ auf nicht erreichbaren Speicher zeigt.
So sollte es gehen:

Code: Alles auswählen

 
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.

Jole
Beiträge: 114
Registriert: Fr 4. Jul 2014, 14:39
OS, Lazarus, FPC: Linux
CPU-Target: amd64

Re: Pointer und Arrays

Beitrag von Jole »

Vielleicht würde ein new (PTBuffer) statt pbuffer:=nil funktionieren.

Nein, dazu müsste TBuffer mit einer Array Dimension vorbelegt sein, z.B so:

Code: Alles auswählen

 
{$mode delphi}
 
Type
  TBuffer = Array[0..9] of Byte;
 
var
  Buf: ^TBuffer;
 
begin
  New (Buf);
  Buf[0]:= 98;
  WriteLn (Buf[0]);
  Dispose (Buf);
 

Dynamisch Speicherplatz erzeugen könnte man mit GetMem (), z.B. so:

Code: Alles auswählen

 
{$mode delphi}
 
Type
  TBuffer = Array of Byte;
 
var
  Buf: ^TBuffer;
 
begin
  GetMem (Buf, 10);
  Buf2[0]:= 128;
  WriteLn (Buf[0]);
  FreeMem (Buf);
  ReadLn;
end.
 

Beide Varianten funktionieren aber nur im Delphi Modus.

Mathias
Beiträge: 6167
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Pointer und Arrays

Beitrag von Mathias »

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.

Dies läuft bei mir fehlerfrei.

Code: Alles auswählen

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

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6200
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Pointer und Arrays

Beitrag von af0815 »

Danke, langsam wird mir das klarer.

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
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: Pointer und Arrays

Beitrag von mse »

Von generics lasse ich die Finger...

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Pointer und Arrays

Beitrag von wp_xyz »

Delphi-Modus bedeutet m.E. nur, dass man das Pointerhäkchen (^) und den Adress-Operator (@) weglassen kann.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6200
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Pointer und Arrays

Beitrag von af0815 »

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. :shock:
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

marcov
Beiträge: 1100
Registriert: Di 5. Aug 2008, 09:37
OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk)
CPU-Target: 32/64,PPC(+64), ARM
Wohnort: Eindhoven (Niederlande)

Re: Pointer und Arrays

Beitrag von marcov »

Jole hat geschrieben:
Vielleicht würde ein new (PTBuffer) statt pbuffer:=nil funktionieren.

Nein, dazu müsste TBuffer mit einer Array Dimension vorbelegt sein, z.B so:


Ah, aber ich alloziere keine TBuffer aber ein PTBuffer. Und PTBuffer ist nur ein pointer nach ein TBuffer, also ein platz.

Danach muss man noch immer setlength(PTBuffer^) machen.

Also

Code: Alles auswählen

 
 
 var P: PTBUFFER;
  new(P); // getmem + initialize nach nul?
  setlength(P^,10);
 
// Deallociezien ist einfacher:
 
Finalize(P^);
dispose(P);
 


Ich mach so etwas mit anistrings, und dynamische arrays sind nicht fundamental anders.

p.s. Ich mach generics :-) Ich nutze die Delphi Syntax in {$mode delphi}. Es gibt auch eine andere Objfpc syntax, aber die nutze ich nicht.

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: Pointer und Arrays

Beitrag von mse »

marcov hat geschrieben:

Code: Alles auswählen

 
Finalize(P^);
dispose(P);
 


Wird "Finalize(P^)" nicht von dispose() ausgeführt und ist daher unnötig?

Jole
Beiträge: 114
Registriert: Fr 4. Jul 2014, 14:39
OS, Lazarus, FPC: Linux
CPU-Target: amd64

Re: Pointer und Arrays

Beitrag von Jole »

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).

marcov
Beiträge: 1100
Registriert: Di 5. Aug 2008, 09:37
OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk)
CPU-Target: 32/64,PPC(+64), ARM
Wohnort: Eindhoven (Niederlande)

Re: Pointer und Arrays

Beitrag von marcov »

mse hat geschrieben:

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.

Jole
Beiträge: 114
Registriert: Fr 4. Jul 2014, 14:39
OS, Lazarus, FPC: Linux
CPU-Target: amd64

Re: Pointer und Arrays

Beitrag von Jole »

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.

Mathias
Beiträge: 6167
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Pointer und Arrays

Beitrag von Mathias »

Das einzige was Sinn macht, ist so etwas, zu TP-Zeiten, als es noch keine Dynamischen Arrayx gab, musste man zu diesm Trick greifen.

Code: Alles auswählen

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

Antworten