Pointer auf Array geht nicht.

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
Mathias
Beiträge: 6938
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Pointer auf Array geht nicht.

Beitrag von Mathias »

Wieso kommt es zu einer Schutzverletzung ?

Code: Alles auswählen

const
  max = 1000;
type
  TVector = array[0..2] of GLfloat;
  PHalbZylinder = ^THalbZylinder;
  THalbZylinder = array[0..max] of TVector;
var
  fHalbZylinderVectoren: THalbZylinder;
  fPHalbZylinderVectoren: ^THalbZylinder;
 
procedure TForm1.InitScene;
var
  i: integer;
begin
  fHalbZylinderVectoren := BerechneHalbZylinder;   // Lädt Array mit Werten.
 
  New(fPHalbZylinderVectoren);
  for i := 0 to Length(fHalbZylinderVectoren) - 1 do begin
    fPHalbZylinderVectoren^[i] := fHalbZylinderVectoren[i];
  end;  
 
  WriteVectoren(fHalbZylinderVectoren);   // Ausgabe kommt richtig.
  WriteVectoren(fPHalbZylinderVectoren^); // Gibt eine Schutzverletzung.
 
end;
 
procedure WriteVectoren(var Vector: array of TVector);
begin
  .......
  Application.MessageBox(PChar(IntToStr(Length(Vector))), 'Vectoren', 0);
end;
 
.....
 
  Dispose (fPHalbZylinderVectoren); // bei Programmende
 
.....
Als Vorlage habe ich dies genommen: http://www.delphi-treff.de/tipps/sonsti ... s/pointer/
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

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

Re: Pointer auf Array geht nicht.

Beitrag von wp_xyz »

Du wirfst hier statische und dynamische Arrays durcheinander. Ein Zeiger auf ein "array of TVector" ist etwas anderes als ein Zeiger auf ein "array[0..1000] of TVector". Da die "1000" wahrscheinlich nur überdimensioniert sind, um Platz für das größtmögliche Array zu schaffen, würde ich stattdessen durchgängig mit dynamischen Arrays arbeiten. Mit "SetLength" belegst du nur den Speicher, den du brauchst, und kannst dir das New/Dispose sparen:

Code: Alles auswählen

 
type
  TVector = array[0..2] of GLfloat;
  THalbZylinder = array of TVector;
 
var
  fHalbZylinderVectoren: THalbZylinder;
 
procedure TForm1.InitScene;
var
  i: integer;
begin
  SetLength(fHalbZylinderVectoren, <soviel wie du brauchst...>);
  fHalbZylinderVectoren := BerechneHalbZylinder;   // Lädt Array mit Werten.
  WriteVectoren(fHalbZylinderVectoren);  
end;
 
procedure WriteVectoren(Vector: THalbZylinder);
begin
  .......
//  Application.MessageBox(PChar(IntToStr(Length(Vector))), 'Vectoren', 0);  // ????
  ShowMessage(Format('%d Vectoren', [Length(Vector)]));
end;
 
// und: kein Dispose nötig!
 

martin_frb
Beiträge: 587
Registriert: Mi 25. Mär 2009, 21:12
OS, Lazarus, FPC: Laz trunk / fpc latest release / Win and other
CPU-Target: mostly 32 bit

Re: Pointer auf Array geht nicht.

Beitrag von martin_frb »

Der param zu WriteVectoren ist nicht ein dynamisches Array, sondern open array.
Und afaik, kann man deshalb auch ein statische array ubergeben.

Aber, es muss (afaik? ) alles auf den stack passen. Und es kann sein das dies hier wegen der groesse von 1000 records nicht passt.

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

Re: Pointer auf Array geht nicht.

Beitrag von Mathias »

Am Stack kann es nicht liegen, das es mit der statischen Array problemlos funktioniert.
Auch ist die Array in der Procedure als var deklariert und somit wird nur ein Zeiger übergeben und nicht die ganze Array.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: Pointer auf Array geht nicht.

Beitrag von Michl »

Ich habe mir mal die Mühe gemacht und Dein geposteten Code kompiliert. Dieser funktioniert bei mir problemlos. (Win64, GLScene-Trunc 1.0.3, Lazarus 1.3 r43677 FPC 2.7.1 i386-win32-win32/win64).
martin_frb hat geschrieben:Aber, es muss (afaik? ) alles auf den stack passen. Und es kann sein das dies hier wegen der groesse von 1000 records nicht passt.
Das sollte er eigentlich bei diesem Beispiel in den allermeisten Fällen (1 x HalbZylinderVector: Array[0..1000] von Array[0..2] von Typ GLFloat (bei mir Single) = 4Byte -> 12012 Byte -> ist ja nun nicht so groß). Anders sieht es aus, wenn Du viele dieser HalbZylinderVectoren deklarierst...

[Edit] eben noch auf Lazarus 1.0.14 getestet, funktioniert auch...

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

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

Re: Pointer auf Array geht nicht.

Beitrag von Mathias »

Das glaube ich nicht, jetzt habe ich den gleichen Code wie gestern Abend kompiliert und es geht auf einmal. :roll:
Ich konnte sogar die For-Schleife ersetzen.

Code: Alles auswählen

  //for i := 0 to Length(fHalbZylinderVectoren) - 1 do begin
  //  fPHalbZylinderVectoren^[i] := fHalbZylinderVectoren[i];
  //end;
  fPHalbZylinderVectoren^ := fHalbZylinderVectoren;
 
// Dies geht jetzt auch mit dem Pointer
  glBufferData(GL_ARRAY_BUFFER, sizeof(fPHalbZylinderVectoren^), fPHalbZylinderVectoren, GL_STATIC_DRAW);
// Ursprünglich ging es nur so
  glBufferData(GL_ARRAY_BUFFER, sizeof(fHalbZylinderVectoren), @fHalbZylinderVectoren, GL_STATIC_DRAW);
 
Vielleicht war gestern irgendwas im Speicher verletzt, als ich mit GetMem bastelte.
Compilieren konnte ich gestern auch ohne Fehler.

Trotdem Danke an alle dir mir halfen. Ich hoffe, das der Fehler nicht mehr auftretet.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

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

Re: Pointer auf Array geht nicht.

Beitrag von Mathias »

Du wirfst hier statische und dynamische Arrays durcheinander. Ein Zeiger auf ein "array of TVector" ist etwas anderes als ein Zeiger auf ein "array[0..1000] of TVector". Da die "1000" wahrscheinlich nur überdimensioniert sind, um Platz für das größtmögliche Array zu schaffen, würde ich stattdessen durchgängig mit dynamischen Arrays arbeiten. Mit "SetLength" belegst du nur den Speicher, den du brauchst, und kannst dir das New/Dispose sparen:
Ich habe unterdessen alles mit dynamischen Arrays gelöst, dies ist viel besser als das obige gepastel.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Antworten