Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Zeiger und Arrays


DrEvil - Di 30.12.03 14:34
Titel: Zeiger und Arrays
Ich habe folgendes Problem: Wenn ein Zeiger auf eine Stelle eines Arrays zeigt kann mann den Wert Problemlos über den Zeiger abrufen, doch wenn man einem zweiten Zeiger eine Stelle des Arrays zuweist, kommt beim Zugriff über den ersten Zeiger ein unheimlich großer und unrealistischer Wert heraus der eindeutig Falsch ist. Ich gehe davon aus das der Zeiger in diesem Fall auf NIL zeigt.
Ich habe schon einiges Probiert und in ähnlichen Zusammenhängen ist das eigentlich kein Problem gewesen. Was kann ich übersehen haben?


Anonymous - Di 30.12.03 14:55

Ohne Code lässt sich das schwer sagen... aber auf nil kann der Pointer nicht zeigen, weil es sonst bei der Dereferenzierung zu einer access violation käme.


DrEvil - Di 30.12.03 15:02

Dazu kommt es auch, sobald man den Wert mit Floattostr in einem Label anzeigen lassen will. Den großen Wert sehe ich nur wenn ich nach dem fehler im Programm die Maus auf den Zeiger halte und sein Wert erscheint.


ErnestoChe - Di 30.12.03 15:36

Hi,

und wieso zeigst du deinen Code nicht?

MFG

- Ernesto -


DrEvil - Fr 02.01.04 21:57

Das Programm verursacht einen Fehler beim auslesen der Zahl über den Zeiger. Dieser Fehler tritt immer bei Allen ausser dem letzten auf. In diesem Fall wäre also Polygon[3] das einzig fehlerfreie.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Edit1: TEdit;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
 end;

Vector = class(TObject)
x,y:real;

  private
    { Private declarations }
  public
    { Public declarations }
  end;

Vector3d = class(TObject)
     x,y,z:real;
     Vector2d:Vector;
     color:Tcolor;
     bSelected:boolean;
  private
    { Private declarations }
  public
    { Public declarations }
  end;



QuadPolygon = class(TObject)
  a,b,c,d:^Vector;
  e,f,g,h:^Vector3d;
  ClippedVertex1,ClippedVertex2:^Vector3d;
  VisibleVertex,InvisibleVertex,Clipped,HalfClipped:Boolean;
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  i,vertexlength,polylength:integer;
  Vertex: array  of Vector3d;
  Polygon: array  of QuadPolygon;
implementation

{$R *.dfm}


procedure TForm1.Button1Click(Sender: TObject);
begin

 for i:= 0 to 3 do
  begin
    inc(polylength);
    SetLength(Polygon,Polylength);
    Polygon[PolyLength-1]:=QuadPolygon.Create;
  end;


 for i:= 0 to 3 do
  begin
     Inc(VertexLength);
     SetLength(Vertex,VertexLength);
     Vertex[VertexLength-1]:=Vector3d.Create;
     Vertex[VertexLength-1].Vector2d:=Vector.Create;
     Vertex[VertexLength-1].x:=1811;   //Dies ist ein beliebiger Testwert.

     Polygon[i].ClippedVertex1:=@Vertex[VertexLength-1];
  end;


end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  for i:= 0 to 3 do
  begin
    Edit1.Text:=Floattostr(Polygon[i].ClippedVertex1^.x);
  end;
end;

end.


Blackbird - Mo 05.01.04 01:18

Also ich denk' mal, dass ich den Grund schon erkannt habe aber das Problem ist, dass sich der Code nicht mal richtig ausführen lässt (Tip: Access Violation wenn man Button2 betätigt), ich also nicht weiss was genau du eigentlich erreichen willst.

Schreib den Code doch bitte noch einmal in Ruhe auf!


Motzi - Mo 05.01.04 10:12

Also erstens mal sind in Delphi alle Objekte bereits Referenzen, du brauchst also nicht mit Pointern auf Objekte arbeiten, da diese bereits solche sind. Zweitens, wieso rufst du innerhalb einer Schleife Setlengt auf um die Länge des Arrays immer um 1 zu erhöhen? Einfacher, schneller und vor allem besser ist diese Variante:

Delphi-Quelltext
1:
2:
3:
  SetLength(Polygon, 4); 
  for i:= 0 to 3 do 
    Polygon[i] := QuadPolygon.Create;


DrEvil - Mo 05.01.04 13:48

zu Blackbird:
Das es zu einer Access Violation nach betätigen des Button2 kommt ist ja gerade das Problem.

zu Motzi:
1)Da ich noch nicht so lange dabei bin, bin ich mir nicht ganz sicher was du damit meinst, dass alle Objekte Referenzen sind.
2)Dies ist ja nur ein vereinfachtes Beispiel Programm um einen Fehler in einem anderen Programm von mir zu verdeutlichen.
Die Frage ist warum sich der Zeiger hier nicht dereferenzieren lässt.


Motzi - Mo 05.01.04 14:11

Referenz ist gleichbedeutend mit Zeiger. In Delphi sind alle Objekte also nur Zeiger an die Stelle im RAM wo dein Objekt liegt. Wenn du also noch selbst mit Zeigern auf Objekten hast, dann hast du quasi einen Zeiger auf einen Zeiger, und das ist dann doch etwas "doppeltgemoppelt"... ;)


DrEvil - Mo 05.01.04 15:23

Vielen Dank für die Antwort. Dann werde ich es mal ohne Zeiger probieren. Trotzdem bleibt die Frage wieso es in diesem Fall nicht funktioniert oder ist das in diesem Kontext generell nicht möglich. In anderen Fällen ging es ohne Probleme. Würde mich jetzt einfach nochmal interessieren.


Blackbird - Di 06.01.04 01:47

Ist im Prinzip ganz einfach...

Das ist es nämlich was ich meinte mit "Schreib den Code doch noch einmal auf!" Dann wär' dir folgender Fehler aufgefallen:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
 for i:= 0 to 3 do 
  begin 
     Inc(VertexLength); 
     SetLength(Vertex,VertexLength); 
     Vertex[VertexLength-1]:=Vector3d.Create; 
     Vertex[VertexLength-1].Vector2d:=Vector.Create; 
     Vertex[VertexLength-1].x:=1811;   //Dies ist ein beliebiger Testwert.


Was ich mein ist:
Zitat:
[VertexLength-1]

Du erzeugst hier immer nur den letzten Vertex und nie die ersten 3!
Vertex[i] wär hier richtig.

Das war meiner Ansicht nach der Grund für die Access Violation.

Desweiteren liegt hier noch ein Fehler:
Nämlich bei: Setlength(Vertex,VertexLength);

Motzi hat hierfür ja schon den richtigen Code gepostet.
Nicht nur, dass dieser besser, einfacher usw. ist - du musst ihn auch so verwenden!
Bei deiner Variante wird bei jedem Aufruf von Setlength dem Array von Delphi ein neuer Speicherbereich zugewiesen (denk ich jedenfalls) - d.h. deine Pointer, die du vorher gesetzt hast zeigen gar net mehr auf den richtigen Speicherbereich, weil sich der Array gar net mehr dort befindet. Deshalb diese völlig verwirrenden Ergebnisse. :wink:

Ich hoff das hat deine Frage beantwortet...alles klar ? 8)

Moderiert von user profile iconPeter Lustig: Code- durch Delphi-Tags ersetzt