Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Array als Pointer übergeben (https://www.delphipraxis.net/187112-array-als-pointer-uebergeben.html)

Captnemo 28. Okt 2015 11:54

Array als Pointer übergeben
 
Hi,

ich will mal was versuchen. Weniger, weil es Sinn macht, sondern nur zu meinem Verständnis. Versucht habe ich das schon, ab hinbekommen habe ich es nicht.

Ich möchte gerne mal ein Array in eine Pointer wandeln und hinterher wieder zurück.

In der ersten Unit:
Delphi-Quellcode:
uses Unit2;

interface

Type
  TMyArray: Array [0..9] of Integer;
.
.
  Type TForm1 = class(TForm)
  .
  .
  private
    MyArray: TMyArray;
  .
  .
  end;

implementation

procedure TForm1.ErzeugeArray;
begin
  for i:=0 to 9 do
    MyArray[i]:=i;
  TesteArray(@MyArray);
end;
und in Unit2:

Delphi-Quellcode:
Type
  TIntArray: array of Intger;

procedure TesteArray(p: Pointer);
begin
  for i:=0 to length(TIntArray(p))-1 do
    TuIrgendwasmit(TIntArray(p)[i]);
end;
So, das wird so sicherlich nicht funktionieren. Aber wie wäre es richtig und warum. Ich hab mich nun durch so einige Beispiele und Tutorials durch gelesen, aber ich raff das einfach nicht.

Bambini 28. Okt 2015 12:01

AW: Array als Pointer übergeben
 
Zitat:

Zitat von Captnemo (Beitrag 1319955)
Delphi-Quellcode:
procedure TForm1.ErzeugeArray;
begin
  for i:=0 to 9 do
    MyArray[i]:=i;
  TesteArray(@MyArray);   // <--- nicht ganz richtig
end;

Eine festes Array of Integer ist <> einem Dynamische array of Integer.
Statt:

Delphi-Quellcode:
 TMyArray: Array [0..9] of Integer;
eine TMyArray: Array of Integer; verwenden und diese mit Setlength() auf 10 setzen.

Captnemo 28. Okt 2015 12:08

AW: Array als Pointer übergeben
 
Zitat:

Zitat von Bambini (Beitrag 1319960)
Delphi-Quellcode:
TesteArray(@MyArray[1]);

Okay, aber warum die 1?

Bambini 28. Okt 2015 12:10

AW: Array als Pointer übergeben
 
Meine erste Antwort war falsch. Habe diese geändert.

Sailor 28. Okt 2015 12:21

AW: Array als Pointer übergeben
 
Du mußt p in TestArray derefenzieren.

SMO 28. Okt 2015 12:31

AW: Array als Pointer übergeben
 
Die 1 ist falsch.

Und zum Grundverständnis: es gibt Unterschiede zwischen statischen Arrays (TMyArray: Array [0..9] of Integer) und dynamischen Arrays (TIntArray: array of Integer). Die solltest du wenn möglich nicht hin und her casten, das kann zu Fehlern führen, wie in deinem Beispiel.

Kurz umrissen: statische Arrays sind ein zusammenhängender Speicherbereich. Die Länge ist nicht explizit vermerkt. Dynamische Arrays sind vergleichbar mit Strings und werden durch Compilermagic unterstützt (z.B. automatisches Freigeben von lokalen DynArray Variablen). Die DynArray Variablen sind implizite Pointer, die auf einen zusammenhängenden Speicherbereich zeigen (auf dem Heap). Direkt vor der Adresse, auf die gezeigt wird, stehen Metadaten, nämlich die Länge des Arrays sowie der RefCount.

Wenn du einen Cast wie "length(TIntArray(p))" machst, dann wird versucht, dieses Längenfeld zu lesen. Aber bei statischen Arrays existiert das gar nicht!


Um Arrays in Pointer umzuwandeln, benutze den Pointertyp, der zum Arrayelement passt. In deinem Beispiel also PInteger.

Delphi-Quellcode:
procedure TesteArray(p: PInteger; Count: Integer);
var
  i: Integer;
begin
  for i := 0 to Count - 1 do
  begin
    TuIrgendwasmit(p^);
    Inc(p); // Pointer auf das nächste Element bewegen
  end;
end;

// oder mit der Direktive POINTERMATH können typisierte Pointer
// direkt wie statische Arrays benutzt werden!

{$POINTERMATH ON}
procedure TesteArray(p: PInteger; Count: Integer);
var
  i: Integer;
begin
  for i := 0 to Count - 1 do
    TuIrgendwasmit(p[i]);
end;

// Aufruf:
var
  MyDynArray: array of Integer;
  MyStaArray: array [0..9] of Integer;

// geht, weil MyDynArray ein impliziter Pointer ist
TesteArray(PInteger(MyDynArray), Length(MyDynArray));

// geht NICHT, weil MyStaArray kein Pointer ist sondern ein 10*4 Bytes großer Speicherbereich
TesteArray(PInteger(MyStaArray), Length(MyStaArray));

// geht, weil sich an der Adresse von MyStaArray direkt der Speicherbereich mit den Elementen befindet
TesteArray(@MyStaArray, Length(MyStaArray));

// geht NICHT, weil sich an der Adresse von MyDynArray nur der implizite Pointer befindet!
TesteArray(@MyDynArray, Length(MyDynArray));


// geht IMMER, egal ob statisches oder dynamisches Array:
TesteArray(@MyStaArray[Low(MyStaArray)], Length(MyStaArray));
TesteArray(@MyDynArray[Low(MyDynArray)], Length(MyDynArray));

// bei dynamischen Arrays ist der niedrigste Index immer 0
// bei statischen Arrays kann man bei der Deklaration den niedrigsten Index auf beliebige Werte setzen,
// aber wenn man konsequent immer 0 benutzt, kann man natürlich schreiben:
TesteArray(@MyStaArray[0], Length(MyStaArray));
TesteArray(@MyDynArray[0], Length(MyDynArray));

Neutral General 28. Okt 2015 12:48

AW: Array als Pointer übergeben
 
Wie die anderen schon gesagt haben: Es ist ein Unterschied ob du ein statisches oder ein dynamisches Array hast:

Statische Arrays:
Delphi-Quellcode:
type
  PIntArray = ^TIntArray ;
  TIntArray = Array[0..9] of Integer;

procedure TForm1.FormCreate(Sender: TObject);
var MyArray: TIntArray;
    i: Integer;
begin
  for i:=0 to 9 do
    MyArray[i]:=i;

  TesteArray(@MyArray);
end;

procedure TForm1.TesteArray(P: Pointer);
var arr: TIntArray;
    i: Integer;
begin
  arr := PIntArray(P)^; // Oder TIntArray(P^)
  for i:=0 to 9 do
    Memo1.Lines.Add(IntToStr(arr[i]));
end;

Dynamische Arrays:
Delphi-Quellcode:
type
  TIntArray = Array of Integer;

procedure TForm1.FormCreate(Sender: TObject);
var MyArray: TIntArray ;
    i: Integer;
begin
  SetLength(MyArray, 10);
  for i:=0 to 9 do
    MyArray[i]:=i;

  TesteArray(Pointer(MyArray)); // Dyn. Arrays sind bereits Pointer
end;

procedure TForm1.TesteArray(P: Pointer);
var arr: TIntArray;
    i: Integer;
begin
  arr := TIntArray(P);
  for i:=0 to 9 do
    Memo1.Lines.Add(IntToStr(arr[i]));
end;
Du kannst diese beiden Array-Typen nicht so ohne weiteres mischen. Zumindest nicht auf "Pointer Ebene".

Wie über mir auch schon gezeigt wurde kannst du auch statt dem Array einen Pointer auf das erste Element des Arrays übergeben (bei beiden Array-Typen wäre das @Array[erster_index]).
Dann kannst du in deiner Methode über einen PInteger auf die Werte des Arrays zugreifen. Allerdings musst du der Methode dann zusätzlich die Anzahl der Elemente übergeben:
Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
var MyArray: TIntArray;
    i: Integer;
begin
  SetLength(MyArray, 10);
  for i:=0 to 9 do
    MyArray[i]:=i;

  TesteArray(@MyArray[0], Length(MyArray)); // Geht bei statischen Arrays genauso
end;

procedure TForm1.TesteArray(P: PInteger; Anzahl: Integer);
var i: Integer;
begin
  for i:=0 to Anzahl-1 do
  begin
    Memo1.Lines.Add(IntToStr(P^));
    inc(P); // Pointer auf das nächstes Element des Arrays setzen
  end;
end;

Captnemo 28. Okt 2015 13:31

AW: Array als Pointer übergeben
 
Vielen Dank. Ihr habt mir sehr weitergeholfen. Und Dank der Erklärung dabei habe ich das auch verstanden. :-D

p80286 28. Okt 2015 14:45

AW: Array als Pointer übergeben
 
Ein Pointer ist eine Speicheradresse, nicht mehr und nicht weniger!
Falls Du eine Definition hast wie
Delphi-Quellcode:
type
 ta = Array [23..24] of Byte;
 tpa = ^ta;
dann wird der Inhalt des Speichers auf den der Pointer zeigt als
Delphi-Quellcode:
Array [23..24] of Byte;
interpretiert.
Zeigt der Pointer auf einen String
Delphi-Quellcode:
var
  p : tpa
  s : string[255];
...

p:=@s;
so wird der Speicherinhalt immer noch als
Delphi-Quellcode:
Array [23..24] of Byte;
interpretiert.

somit ist "Array als Pointer übergeben" nicht möglich. Möglich wäre es die Adresse eines Arrays zu übergeben wobei Du bei Dynamischen Array zwischen dem Inhalt des Arrays
Delphi-Quellcode:
@Myarray[0]
und der Array-Variablen
Delphi-Quellcode:
@MyArray
unterscheiden mußt. Bei statischen Arrays ist @MyArray=@MyArray[0]

Gruß
K-H

Captnemo 28. Okt 2015 15:11

AW: Array als Pointer übergeben
 
Zitat:

Zitat von p80286 (Beitrag 1319995)
somit ist "Array als Pointer übergeben" nicht möglich. Möglich wäre es die Adresse eines Arrays zu übergeben wobei Du bei Dynamischen Array zwischen dem Inhalt des Arrays
Delphi-Quellcode:
@Myarray[0]
und der Array-Variablen
Delphi-Quellcode:
@MyArray
unterscheiden mußt. Bei statischen Arrays ist @MyArray=@MyArray[0]

Gruß
K-H

Okay, bis eben dachte ich, ich hätt's verstanden ;)Und dann machst du sowas :-D

Ich dachte eigentlich immer im Pointer steht die Adresse?


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:15 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz