Autor |
Beitrag |
j0hnny
      
Beiträge: 30
|
Verfasst: So 21.11.10 02:44
Guten Tag!
Ich habe eine Prozedur, der ein Pointer (PSingle) auf ein 2D-Single-Array (array of array of Single) übergeben wird.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22:
| var Matrix : array of array of Single; ... setlength(Matrix,N,M); ... bla(@Matrix); ... procedure bla(Matrix : PSingle;N,M:LongWord); var x,y : LongWord; PMatrix : PSingle; sum : Single; begin PMatrix:=Matrix; for y := 0 to M-1 do begin for x := 0 to N-1 do begin sum:=sum+PMatrix^; inc(PMatrix); end; end;
end; |
Irgendwie schaffe ich aber nicht, dass ich mittels Pointern auf die Werte des Arrays zugreifen kann. Was mach ich falsch?
EDIT: Anscheinend muss man PSingle(PMatrix)^ schreiben um an den Pointer-Wert zu gelangen, oder? Und muss ich eigentlich inc(PMatrix) oder inc(PMatrix,3) benutzen?
|
|
jaenicke
      
Beiträge: 19312
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: So 21.11.10 03:51
j0hnny hat folgendes geschrieben : | Ich habe eine Prozedur, der ein Pointer (PSingle) auf ein 2D-Single-Array (array of array of Single) übergeben wird. |
Wo?
Ich sehe nur eine Prozedur, der ein Pointer auf einen Single übergeben wird.
Und warum willst du einen Pointer auf einen Pointer? Deine Variable Matrix ist ein impliziter Pointer auf ein dynamisches Array. Und jetzt nimmst du wiederum dessen Adresse und übergibst die.
Kleines Beispiel, im Browser getippt, sollte 30 und 1 ausgeben: 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:
| type TExample = array of array of Single;
function Example(a: TExample): Single; var i: Integer; j: Integer; begin Result := 0; for i := Low(a) to High(a) do for j := Low(a[i]) to High(a[i]) do begin Result := Result + a[i, j]; a[i, j] := a[i, j] + 1; end; end;
var Test: TExample; i, j: Integer; ExampleResult: Single; begin SetLength(Test, 3, 4); for i := Low(Test) to High(Test) do for j := Low(Test[i]) to High(Test[i]) do Test[i, j] := i + j; ExampleResult := Example(Test); ShowMessage(FloatToStr(ExampleResult) + ', Test[0, 0] = ' + FloatToStr(Test[0, 0])); end; | Denn der Wert von Test[0, 0] ist 0 und wird in der Funktion Example um 1 erhöht. Da es ein Pointer ist, kommt die Änderung im ursprünglichen Array an.
|
|
j0hnny 
      
Beiträge: 30
|
Verfasst: So 21.11.10 12:24
Danke erstmal für die Antwort.
Also wie ich dynamische Arrays übergebe weiß ich quasi schon. Aber ich will eine Komponente schreiben, die unabhängig von der Deklaration des dynamischen Arrays ist.
Ich weiß, dass es reicht bei 1D-Arrays den Pointer auf den ersten Array-Eintrag zu übergeben. Dann kann man den Pointer mit inc() erhöhen und erhält den nächsten Eintrag.
Oder geht das Ganze vielleicht auch eleganter? Ich will auf die Werte des 2D-Arrays zugreifen, ohne dass irgendwo im Speicher eine Kopie erzeugt werden muss.
Also das ganze mal als Beispiel:
Ich habe ein Programm in der ich einen 2D-Array mit TMatrix = array of array of Single deklariere. In der Komponente will ich nun auf die Werte des 2D-Arrays zugreifen. Mit der Übergabe von dynamischen Arrays müsste ich ja bei beiden dieselbe Array-Deklaration benutzen. Beides soll aber unabhängig voneinander sein. Am besten wäre, wenn ich in der Komponente auf ohne Pointer auf die Array-Werte zugreifen könnte, da ich Zeilen- und Spalten-Operationen brauche, die mit Pointern etwas kompliziert werden.
Gibt es eine Möglichkeit in der Komponente eine eigene Definition T2DArray = array of array of Single zu machen und dann damit auf TMatrix zuzugreifen? Und dass, dass alle Werte von T2D-Array auf TMatrix zeigen, sodass ich keine Kopie der Matrix im Speicher haben muss?
Grüße
|
|
bummi
      
Beiträge: 1248
Erhaltene Danke: 187
XP - Server 2008R2
D2 - Delphi XE
|
Verfasst: So 21.11.10 12:42
Für eine Komponente könntest Du die Matrix in der Komponente und nur in der Komponente verwalten.
Wenn Du die Matrix außerhalb verwalten möchtest kannst Du einen Setter schreiben der die Adresse der Matrix bekommt. Zugreifen kannst Du dann über Tuwas(x,y).
Die Gültigkeit des Zugriffs kannst Du über
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| ok := (x<= High(FMatrix)) and (y<=High(FMatrix[x])); if ok then begin
end else Raise Exception.Create('Ungültiger Zugriff') |
regeln.
_________________ Das Problem liegt üblicherweise zwischen den Ohren H₂♂
DRY DRY KISS
|
|
j0hnny 
      
Beiträge: 30
|
Verfasst: So 21.11.10 13:04
Das Problem ist, dass die Komponente komplett unabhängig laufen soll. Ich arbeite mit OpenGL und dort muss ich für Texturen auch eine 2D-Matrix-3Byte übergeben. Das mache ich über GetMem(data,N*M*3); und gehe dann über inc(data) die Werte durch.
Ähnliches will ich jetzt auch mit einem dynamischen Array machen. Das Komische ist, dass bei 1D-Arrays die Werte einfach über Pointer angesprochen werden können. Aber bei bla(@Matrix[0,0]) geht das nur bei der erste Zeile gut.
Am liebsten würde ich mir allerdings die Sache mit den Pointern sparen. Ich will wie gesagt auf den Werte eines übergebenen 2D-Arrays zugreifen. Am liebsten auf über Indizes (X,Y). Sowas müsste doch eigentlich auch einfach gehen oder? Kann doch nicht sein, dass man, wenn man TMatrix = array of array of Single übergibt nur darauf zugreifen kann, wenn man die original Deklaration hat. Und eine Umwandlung von TMatrix = array of array of Single müsste doch eigentlich auch in ein T2DArray = array of array of Single möglich sein. Ist doch quasi das gleiche.
Geht nicht irgendwie sowas wie:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| type TMatrix : array of array of Single; TArray2D : array of array of Single; ... var Matrix : TMatrix; Array2D : TArray2D; PArray2D : ^TArray2D; ... setlength(Matrix,10,10); Matrix[5,5]:=123; PArray2D:=@Matrix[0,0]; Showmessage(FloatToStr(PArray^[5,5])); |
|
|
jaenicke
      
Beiträge: 19312
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: So 21.11.10 13:29
Du kannst ein dynamisches Array auch auf den konkreten Arraytyp casten bei der Übergabe. Aber mit sowas hebelst du natürlich die komplette Typsicherheit, die ja gerade einer der Vorteile von Delphi ist, aus.
Und ob dann die Referenzzählung und damit die Freigabe des Speichers immer korrekt funktioniert, weiß ich auch nicht.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| var Test: array of array of Single; i, j: Integer; ExampleResult: Single; begin SetLength(Test, 3, 4); for i := Low(Test) to High(Test) do for j := Low(Test[i]) to High(Test[i]) do Test[i, j] := i + j; ExampleResult := Example(TExample(Test)); ShowMessage(FloatToStr(ExampleResult) + ', Test[0, 0] = ' + FloatToStr(Test[0, 0])); | Sinnvoll sind solche Tricksereien aber nicht. Der Benutzer deiner Funktion braucht doch ohnehin die konkrete Deklaration um zu wissen was er übergeben muss.
Das Problem bei Pointern:
Ein dynamisches Array ist ein Pointer auf den eigentlichen Datenbereich. Wenn du also ein zweidimensionales Array hast, hast du einen Pointer auf ein Array aus Pointern auf die Datenbereiche...
Dementsprechend kannst du auch nicht auf die einzelnen Werte so einfach zugreifen, wenn du nicht weißt, was für ein Array und damit welches Speicherlayout dahintersteckt.
Du kannst natürlich den Benutzer selbst die Daten in einen Puffer schreiben lassen und dann den Puffer und dessen Größe dir geben lassen. Das hat aber nichts mit Optimierung oder Performance zu tun, sondern macht das ganze nur unnötig kompliziert, langsam und fehleranfällig. 
|
|
bummi
      
Beiträge: 1248
Erhaltene Danke: 187
XP - Server 2008R2
D2 - Delphi XE
|
Verfasst: So 21.11.10 15:09
wenn ich das richtig sehe muß Deine Komponenete im Rumpf so aussehen:
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 pRGBTripleArray = ^TRGBTripleArray; TRGBTripleArray = ARRAY[0..$effffff] OF TRGBTriple; TMyKomp=Class(TBitmap) published private function GetDasArray: pRGBTripleArray; published public Constructor CreatewithInfo(x,y:Integer); Published Property DasArray:pRGBTripleArray read GetDasArray; End;
implementation
constructor TMyKomp.CreatewithInfo(x, y: Integer); begin inherited Create; PixelFormat := pf24Bit; width := x; height := y; end;
function TMyKomp.GetDasArray: pRGBTripleArray; begin Result := Scanline[0]; end; |
Du hast keine Array of Array of Single sondern wenn überhaupt dann ein Array of Array of TRGBTriple,
das wiederum dem Datenbereich einer 24-Bittigen Bitmaps entspricht, auf welches Du z.B. so zugreifen kannst
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| for Y := 0 to bmp.Height -1 do begin pscanLine := bmp.Scanline[y]; for x := 0 to bmp.Width -1 do begin pscanLine[x].rgbtBlue := pscanLine[x].rgbtBlue XOR 255; pscanLine[x].rgbtGreen := pscanLine[x].rgbtGreen XOR 255; pscanLine[x].rgbtRed := pscanLine[x].rgbtRed XOR 255; end; end; |
DasArray wäre auch das was dann OpenGL zugewiesenm würde.
_________________ Das Problem liegt üblicherweise zwischen den Ohren H₂♂
DRY DRY KISS
|
|
j0hnny 
      
Beiträge: 30
|
Verfasst: So 21.11.10 16:43
Danke für die Antworten.
Dann werde ich das wohl doch so machen müssen, dass ich mit der Komponente die Deklaration liefere. Im Notfall muss der Nutzer halt casten.
Das mit dem OpenGL war nur als Beispiel gemeint. Ich rechne in meinem Programm ein array of array of Single in ein Falschfarbenbild um. Aber gut zu wissen, dass es auch ohne Pointer geht
Grüße
|
|
|