Autor |
Beitrag |
huhn
      
Beiträge: 272
Erhaltene Danke: 1
WIN XP
D7Pers
|
Verfasst: 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
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):
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:PContArr; procedure init(Container:array of TCont); 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 if d[0]^.Kind=1 then .... end; |
Was mach ich falsch?
mfg huhn
_________________ Quod Erat Demonstrandum-Was zu beweisen war! *THX to Chrissivo!*
|
|
Motzi
      
Beiträge: 2931
XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
|
Verfasst: 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!
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| type PContArr = array of PCont; procedure TVektorLabel.init(Container: array of TCont); d := @Container; |
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 
      
Beiträge: 272
Erhaltene Danke: 1
WIN XP
D7Pers
|
Verfasst: 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?
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(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
      
Beiträge: 2931
XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
|
Verfasst: Di 18.07.06 15:19
Warum nicht einfach so?
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); 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; |
_________________ gringo pussy cats - eef i see you i will pull your tail out by eets roots!
|
|
huhn 
      
Beiträge: 272
Erhaltene Danke: 1
WIN XP
D7Pers
|
Verfasst: 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...
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; procedure init(Container:array of TCont); published ... end;
procedure TVektorLabel.init(Container:array of TCont); begin d:=@Container; showmessage(inttostr(length(d))+'__'+inttostr(length(Container))); showmessage(d[0].name);end; |
_________________ Quod Erat Demonstrandum-Was zu beweisen war! *THX to Chrissivo!*
|
|
Motzi
      
Beiträge: 2931
XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
|
Verfasst: Di 18.07.06 16:14
Ich hab mir das nochmal ganz genau angeschaut. Wenn deine Prozedur einen array of TCont entegegennimmt:
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):
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:
Delphi-Quelltext 1: 2:
| var x: array [0..10] of 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 
      
Beiträge: 272
Erhaltene Danke: 1
WIN XP
D7Pers
|
Verfasst: Di 18.07.06 20:51
Vielen dank motzi
Endresultat sieht so aus und funktioniert:
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); 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 
      
Beiträge: 272
Erhaltene Danke: 1
WIN XP
D7Pers
|
Verfasst: 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
      
Beiträge: 2931
XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
|
Verfasst: 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 
      
Beiträge: 272
Erhaltene Danke: 1
WIN XP
D7Pers
|
Verfasst: 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
      
Beiträge: 2931
XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
|
Verfasst: 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:
Delphi-Quelltext 1: 2: 3:
| type TContArray = array of TCont; PContArray = ^TContArray; |
Die Klasse schaut dann so aus:
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; procedure init(Container: PContArray); published ... end;
procedure TVektorLabel.init(Container: PContArray); begin d := Container; end;
procedure TVektorLabel.bla...; begin for z := Low(d^) to high(d^) do if d^[i].Kind = 1 then .... end; |
Beim Aufruf von init muss nun natürlich der Zeiger auf ein TContArray übergeben werden:
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 
      
Beiträge: 272
Erhaltene Danke: 1
WIN XP
D7Pers
|
Verfasst: 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!*
|
|