Autor Beitrag
huhn
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 272
Erhaltene Danke: 1

WIN XP
D7Pers
BeitragVerfasst: Di 18.07.06 13:58 
Hi,
mein problem ist, dass ich eine Fehlermeldung bekomme und mir nicht so ganz klar ist wieso.
In meinen Mainprog hab ich die variable
ausblenden Delphi-Quelltext
1:
var data: array of TCont;					

wobei ich diese meiner visuellen komponente übergeben will(als nur einen zeiger auf dieses array), mittels einer procedure.
Meine visuelle kompo sieht dabei gekürzt so aus(hab mehrere versuche gemacht, es will aba net so ganz):
ausblenden volle Höhe 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:
type TCont = record
      name:shortstring;
      case Kind:integer of
        1: (Point:TKoord);
        2: (Line:TLine);
        3: (Plane:TPlane);
  end;
type PCont = ^TCont;
type PContArr = array of PCont;

type
  TVektorLabel = class(TGraphicControl)
  ...
  public
    //d: array of ^TCont; //erster Versuch
    d:PContArr;           //zweiter Versuch
    procedure init(Container:array of TCont);
    { Public-Deklarationen }
  published
  ...
  end;

procedure TVektorLabel.init(Container:array of TCont);
begin
  d:=@Container;
end;

procedure TVektorLabel.bla...;
begin
  for z:=0 to high(d) do
    begin
    //beide gehen nicht, hier kommt die Fehlermeldung
    //if d[0].Kind=1 then ....
    if d[0]^.Kind=1 then ....
end;

Was mach ich falsch?
mfg huhn

_________________
Quod Erat Demonstrandum-Was zu beweisen war! *THX to Chrissivo!*
Motzi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2931

XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
BeitragVerfasst: Di 18.07.06 14:18 
Zwei Sachen:
Erstens: dynamische Arrays sind bereits Pointer die nur implizit dereferenziert werden (@Container ist dann also ein Pointer auf einen Pointer)
Zweitens: du vermischst da verschiedene Typen!
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
type PContArr = array of PCont; // PContArray ist also ein Array das Pointer enthält

procedure TVektorLabel.init(Container: array of TCont); // Container ist ein Array das _komplette Records_ enthält

d := @Container; // d erhält damit die Adresse eines Arrays das _komplette Records_ enthält!
                 //laut definition ist d aber ein Array mit Pointern auf Records!

Erkennst du deinen Fehler?
Wie du ihn am besten löst kann ich dir nicht sagen, da ich nicht genau weiß was du vorhast und es gibt unterschiedliche Möglichkeiten..

Gruß, Motzi

_________________
gringo pussy cats - eef i see you i will pull your tail out by eets roots!
huhn Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 272
Erhaltene Danke: 1

WIN XP
D7Pers
BeitragVerfasst: Di 18.07.06 14:31 
aja ok also das mit dem PCont leuchtet mir ein, aba wie mach ich es dann bei einem dynamischen Record?
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
procedure TVektorLabel.init(Container:array of TCont);
var p:Pointer;
begin
  d:=@Container;
  p:=@Container;
  //showmessage(TContArr(p)[0].Name);
  showmessage(floattostr(high(TContArr(d)))+'--'+
              TContArr(d)[1].name);  
end;

wenn ichs so mach funktionierts nur die länge stimmt nicht xD und laut pointer tut wird das au net gern gesehen^^

An sich möchte ich die daten aus dem record mit meiner visuellen kompo nur darstellen und wollte deswegen das array aus dem hauptprogramm übergeben. so dass wenn ich was im hauptprog ändere im array sich das auch auf die vis kompo auswirkt und er beim nächsten neuzeichnen des zeichnet

_________________
Quod Erat Demonstrandum-Was zu beweisen war! *THX to Chrissivo!*
Motzi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2931

XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
BeitragVerfasst: Di 18.07.06 15:19 
Warum nicht einfach so?
ausblenden volle Höhe 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:
type TCont = record
      name:shortstring;
      case Kind:integer of
        1: (Point:TKoord);
        2: (Line:TLine);
        3: (Plane:TPlane);
  end;

type TContArr = array of TCont;

type
  TVektorLabel = class(TGraphicControl)
  ...
  public    
    d: TContArr;
    procedure init(Container: TContArray);
    { Public-Deklarationen }
  published
  ...
  end;

procedure TVektorLabel.init(Container: TContArray);
begin
  d := Container; // ein dynamisches Array ist bereits ein Pointer - daher wird hier nur der Pointer kopiert!
end;

procedure TVektorLabel.bla...;
begin
  for z := Low(d) to high(d) do
    if d[0].Kind = 1 then ....
end;

_________________
gringo pussy cats - eef i see you i will pull your tail out by eets roots!
huhn Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 272
Erhaltene Danke: 1

WIN XP
D7Pers
BeitragVerfasst: Di 18.07.06 15:23 
Hab mich nomal schlau gemacht und des berücksichtigt was du gesagt hast Motzi,
thx ;)
Mein problem scheint leider die größe/länge des arrays zu sein, die ich nicht richtig rausbekomme...
ausblenden 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:
type TCont = record
      name:shortstring;
      case Kind:integer of
        1: (Point:TKoord);
        2: (Line:TLine);
        3: (Plane:TPlane);
  end;

type
  TVektorLabel = class(TGraphicControl)
  ...
  public
    d: array of TCont; //wenn ein array schon en Pointer is^^
    procedure init(Container:array of TCont);
    { Public-Deklarationen }
  published
  ...
  end;

procedure TVektorLabel.init(Container:array of TCont);
begin
  d:=@Container;
  showmessage(inttostr(length(d))+'__'+inttostr(length(Container)));//die länge stimmt nicht und deswegen gab es immer fehler
  showmessage(d[0].name);//gibt mir das richtige aus
end;

_________________
Quod Erat Demonstrandum-Was zu beweisen war! *THX to Chrissivo!*
Motzi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2931

XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
BeitragVerfasst: Di 18.07.06 16:14 
Ich hab mir das nochmal ganz genau angeschaut. Wenn deine Prozedur einen array of TCont entegegennimmt:
ausblenden Delphi-Quelltext
1:
procedure init(Container:array of TCont);					

Dann wird intern eine Kopie dieses Arrays angelegt (damit sich eventuelle Änderungen eben NICHT auf das übergebene Array auswirken).
Wenn du hingegen einen eigenen Typ definierst (so wie ich in meinem vorherigen Posting):
ausblenden Delphi-Quelltext
1:
type TContArr = array of TCont;					

Dann wird diese lokale Kopie nicht erstellt. Und dann reicht auch eine einfache Zuweiseung ohne "@". (Im Gegenteil - hier wäre das @ dann sogar ein Fehler!). Außerdem stimmt dann auch das Resultat von length(d).

Das Problem mit dem Parameter Container: array of TCont ist, dass dynamische und statische Arrays vermixt werden können. Ein solcher Aufruf ist ohne Probleme möglich:
ausblenden Delphi-Quelltext
1:
2:
var x: array [0..10of TCont;
VektorLabel.init(x);

In deiner Init-Funktion weißt du die Adresse des übergebenen Array dann einem dynamischen Array zu. Nur führt ein dynamisches Array an den negativen Offsets noch einen Referenz- und Längenzähler mit. Das statische Array hat diese nicht. Bei length(<dynArray>) wird einfache dieser Längenzähler am Offset -4 abgefragt. Nachdem dein Pointer aber auf ein statisches Array zeigt kommt dabei nur Müll raus!

Daher: für bessere Typsicherheit - einen eigenen Typ TContArray definieren!

Gruß, Motzi

_________________
gringo pussy cats - eef i see you i will pull your tail out by eets roots!
huhn Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 272
Erhaltene Danke: 1

WIN XP
D7Pers
BeitragVerfasst: Di 18.07.06 20:51 
Vielen dank motzi ;)
Endresultat sieht so aus und funktioniert:
ausblenden 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:
type TCont = record
      name:shortstring;
      case Kind:integer of
        1: (Point:TKoord);
        2: (Line:TLine);
        3: (Plane:TPlane);
  end;
type TContArr = array of TCont;

type
  TVektorLabel = class(TGraphicControl)
  ...
  public    
    d: TContArr;
    procedure init(Container: TContArray);
    { Public-Deklarationen }
  published
  ...
  end;

procedure TVektorLabel.init(Container: TContArray);
begin
  d := Container; 
end;

procedure TVektorLabel.bla...;
begin
  for z := Low(d) to high(d) do
    if d[0].Kind = 1 then ....
end;

Jop du hast recht es stimmt!
Nomal big big thx!!!
ich denke der Thread wird auch vielen anderen helfen ;)
also bedankt euch alle bei Motzi!
mfg huhn

//edit: ich bins nomal wenn ich änderungen im hauptprg das array (dynam) ändere wirkt sich dies nicht auf die kompo aus, was sie ausgibt und das wollt ich ja *heul*
wie bekommt man das auch noch variabel hin? kann ich nicht den negativen offset manuell irgendwie auslesen?

_________________
Quod Erat Demonstrandum-Was zu beweisen war! *THX to Chrissivo!*
huhn Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 272
Erhaltene Danke: 1

WIN XP
D7Pers
BeitragVerfasst: Di 18.07.06 22:00 
Soweit ichs getestet habe hast du soweit recht und es funktioniert auch (das mit den offset wusst ich nicht und habs gleich mal nachgeschlagen).
Die Änderung, soweit es den Inhalt der records betrifft wird auch bei meiner kompo angezeigt, jedoch wenn ich in meinen hauptprog das dyn Array vergrößere interessiert es meinen Pointer in der Kompo nicht da er statisch ist. Meine Frage ist wie bekomme ich noch das hin das dies auch dynamisch wird, dh das auch änderungen in der größe des records sichtbar werden in meiner visuellen komponente?

setlength innerhalb der visuellen Kompo funktioniert net, is au klar^^

mfg equi

ps.: ich nehm mal an das man eine dynamische übergabe nicht schaft oda?

_________________
Quod Erat Demonstrandum-Was zu beweisen war! *THX to Chrissivo!*
Motzi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2931

XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
BeitragVerfasst: Di 18.07.06 23:42 
Alles über Referenz- und Längenzähler an den negativen Offsets kannst du in meinem String-Tutorial auf www.manuel-poeter.de nachlesen. Intern sind Strings nicht viel anders als dynamische Arrays (of Char).

Sobald die Länge des Arrays geändert wird, wird intern ReallocMem aufgerufen. D.h. es wird ein neuer Speicherblock in der entsprechenden Größe für das Array reserviert, der Inhalt des Arrays verschoben und der Zeiger verweist nun auf den neuen Speicherblock. Das Problem ist nur, dass der Zeiger in der Komponente noch immer auf den alten Speicherblock zeigt.
Entweder du aktualisierst also nochmal den Zeiger in der Komponente, oder aber es wird nochmal eine Stufe komplizierter mit Zeigern auf Zeiger (bei Interesse für nähere Ausführung sag Bescheid..).

Gruß, Motzi

_________________
gringo pussy cats - eef i see you i will pull your tail out by eets roots!
huhn Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 272
Erhaltene Danke: 1

WIN XP
D7Pers
BeitragVerfasst: Mi 19.07.06 16:47 
Jop bin interessiert an der Zeiger auf Zeiger Methode!^^
Des Tut schau ich mir glei au nomal an ;)
mfg equi

_________________
Quod Erat Demonstrandum-Was zu beweisen war! *THX to Chrissivo!*
Motzi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2931

XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
BeitragVerfasst: Mi 19.07.06 18:40 
Gut.. es ist eigentlich nicht schwer, birgt aber gewisse Gefahren. Neben dem Typ TContArray wird einfach noch ein Zeiger auf diesen Typ definiert:
ausblenden Delphi-Quelltext
1:
2:
3:
type
  TContArray = array of TCont;
  PContArray = ^TContArray;

Die Klasse schaut dann so aus:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
type
  TVektorLabel = class(TGraphicControl)
  ...
  public    
    d: PContArray; // Zeiger auf Array
    procedure init(Container: PContArray);
    { Public-Deklarationen }
  published
  ...
  end;

procedure TVektorLabel.init(Container: PContArray);
begin
  d := Container;
end;

procedure TVektorLabel.bla...;
begin
  for z := Low(d^) to high(d^) do // hier muss nun natürlich überall dereferenziert werden!
    if d^[i].Kind = 1 then ....
end;

Beim Aufruf von init muss nun natürlich der Zeiger auf ein TContArray übergeben werden:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
var
  x: TContArray;

  SetLength(x, 10);
  init(@x);

Im Endeffekt erhält die Komponente einen Zeiger auf eine Stelle im Speicher, an der die Adresse des erstem Array-Elements steht. Wird nun die Länge des Arrays verändert, so wird die neue Adresse des Arrays an dieser Stelle aktualisiert. Wir arbeiten also mit einem Zeiger auf einen Zeiger.

Die Gefahr dabei ist jedoch folgende: angenommen der obige Code, mit der Variablen x die an init übergeben wird, stammt aus einer beliebigen Methode und x ist eine lokale Variable dieser Methode. Dann räumt Delphi am Ende der Methode automatisch auf, das dynamische Array wird freigegeben und die Variable x verliert ihre Gültigkeit. Der Zeiger in der Komponente zeigt aber weiterhin auf jene Speicherstelle an der die Variable x war. Und das nächste mal wenn die Komponente auf die Daten aus dem Array zugreifen will, dann wird eben der Wert, der an dieser Stelle im Speicher steht, wieder als Adresse interpretiert und dort nach dem ersten Array-Element gesucht. Da eine lokale Variable auf dem Stack abgelegt ist und der Zeiger somit auf den Stack zeigt, ist nicht vorhersehbar was für einen Wert zu diesem Zeitpunkt an dieser Stelle steht -> die AccessViolation ist vorprogrammiert!
Du musst in diesem Fall also immer aufpassen wann eine Variable ihre Gültigkeit verliert und dementsprechend den Zeiger der Komponente uuf nil setzen.

Gruß, Motzi

_________________
gringo pussy cats - eef i see you i will pull your tail out by eets roots!
huhn Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 272
Erhaltene Danke: 1

WIN XP
D7Pers
BeitragVerfasst: Do 20.07.06 00:28 
Ok thx,
des funktioniert ;) man muss jedoch, wie du schon indirekt gesagt hast im oncreate teil die länge auf 1 setzen und es übergeben da es sonst wurstsalat gibt^^

_________________
Quod Erat Demonstrandum-Was zu beweisen war! *THX to Chrissivo!*