Autor Beitrag
j0hnny
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 30



BeitragVerfasst: 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.

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:
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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19312
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 21.11.10 03:51 
user profile iconj0hnny hat folgendes geschrieben Zum zitierten Posting springen:
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. :gruebel:

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:
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:
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, 34);
  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[00]));
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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 30



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1248
Erhaltene Danke: 187

XP - Server 2008R2
D2 - Delphi XE
BeitragVerfasst: 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
ausblenden 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 30



BeitragVerfasst: 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:
ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19312
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: 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. :roll:
Und ob dann die Referenzzählung und damit die Freigabe des Speichers immer korrekt funktioniert, weiß ich auch nicht.
ausblenden 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, 34);
  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[00]));
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. :nixweiss:
bummi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1248
Erhaltene Danke: 187

XP - Server 2008R2
D2 - Delphi XE
BeitragVerfasst: So 21.11.10 15:09 
wenn ich das richtig sehe muß Deine Komponenete im Rumpf so aussehen:
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
  pRGBTripleArray = ^TRGBTripleArray;
  TRGBTripleArray = ARRAY[0..$effffffOF TRGBTriple;
  TMyKomp=Class(TBitmap)
  published
  private
    function GetDasArray: pRGBTripleArray;
  published
     public
       Constructor CreatewithInfo(x,y:Integer);
     Published
       Property DasArray:pRGBTripleArray read GetDasArray;
  End;

implementation

{ TMyKomp }

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

ausblenden 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 30



BeitragVerfasst: 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