Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Funktionsrückgabewert: Array (https://www.delphipraxis.net/121246-funktionsrueckgabewert-array.html)

violinenspieler1000 24. Sep 2008 13:59


Funktionsrückgabewert: Array
 
Hallo,

ich möchte eine Funktion schreiben, die mir als Rückgabewert ein (mehrdimensionales) Array liefert.

Geht sowas? Wie kann man das relaisieren?


Thomas

DeddyH 24. Sep 2008 14:01

Re: Funktionsrückgabewert: Array
 
Das müsste gehen, wenn Du das Array als Typ deklarierst und die Funktion dann diesen Typ zurückgibt.

DP-Maintenance 24. Sep 2008 16:20

DP-Maintenance
 
Dieses Thema wurde von "Jelly" von "Klatsch und Tratsch" nach "Object-Pascal / Delphi-Language" verschoben.
Klatsch & Tratsch ist das aber noch nicht :-)

SirThornberry 24. Sep 2008 16:44

Re: Funktionsrückgabewert: Array
 
Zitat:

Zitat von violinenspieler1000
...Geht sowas?...

Was spricht dagegen es einfach zu probieren? :gruebel:

sx2008 25. Sep 2008 03:15

Re: Funktionsrückgabewert: Array
 
Zitat:

Zitat von violinenspieler1000
ich möchte eine Funktion schreiben, die mir als Rückgabewert ein (mehrdimensionales) Array liefert.

Kannst du mal dein ursprüngliches Problem schildern?
Es ist günstig, mehrdimensionales Arrays in einer Klasse zu verpacken.
Das hat den Vorteil, dass du alle Funktionen, die sich auf das Array beziehen in der Klasse unterbringen kannst.
Insbesondere Sparse-Arrays lassen sich nur mit Klassen sinnvoll implementieren.
Genaueres kann man aber erst sagen, wenn man weiss, was du vorhast.

oki 25. Sep 2008 06:38

Re: Funktionsrückgabewert: Array
 
Moin,

bei der Übergabe in Funktionen/Proceduren werden Arrays angegeben wie dynamische Arrays. Dabei sollte es egal sein, ob ein- oder mehrdimensional.
Delphi-Quellcode:
Procedure SetArr(Value : Array of Integer);
Die Methode mit der Typdeklaration wurde ja schon benannt.
Delphi-Quellcode:
type
  TDeclArray = Array [0..Max] of Integer;

Procedure SetArr(Value : TDeclArray);
Im ersten Fall kannst Arrays beliebiger Länge übergeben, im Zweiten nur vom deklarierten Typ.
Achte bei dem Hinweis für die Klassen darauf, dass du Arrays nicht im published-Teil als Typ angegen kannst.

Gruß oki

edit: Sorry, imho gilt das natürlich auch für Rückgabewerte von Funktionen. Im Fall Published sind natürlich propertys gemeint.

Roachford 25. Sep 2008 12:56

Re: Funktionsrückgabewert: Array
 
Dynamische Arrays als Rückgabewert sind programmiertechnisch mehr als ineffizient, da der Rückgabewert immer kopiert wird. Es lohnt sich somit definitiv nicht, wenn dann eher als VAR Parameter übergeben und dann in der Funktion füllen.

ABER: dynamische Arrays etc. sind nur noch an wenigen Stellen sinnvoll einsetzbar, da die Nachteile überwiegen:

Vorteile:
- Member sind vom direkten Typ

Nachteile:
- man muss genau sein beim Handling, vor allem bei Übergaben, da es sonst leicht und viel kopiert wird von Delphi und somit der Speicherverbrauch steigt
- Erhöhter Aufwand beim entfernen einzelner Member
- Man explizit drauf achten by reference Übergaben zu deklarieren, damit man das Array in Funktionen ändern kann, ansonsten arbeitet man auf einer Kopie

TList und deren Derivate ersetzen die dynamischen Arrays mit einer z.T. effizienteren Verwaltung (löschen eines Elementes schiebt in TList nur die Zeiger, in einem Array Of müssen die Elemente, also der Inhalt, bewegt werden, was meist ungemein grösser ist)

oki 25. Sep 2008 13:03

Re: Funktionsrückgabewert: Array
 
Hi,

da ich mir jetzt nicht sicher bin formuliere ich es mal als Aussage und Frage.

Dynamische Arrays sind imho Zeiger auf Speicherbereiche. Das Setzen einer Variable auf nil die ein dynamisches Array hält reicht aus um das Array zu "lösche".
Somit sollte eine Übergabe eines dyn. Arrays in einer Procedure doch die Übergabe eines Zeigers sein. Ist dann überhaupt eine Deklaration als var-Parameter notwendig?

Das es bei der Übergabe von dyn. Arrays in Procedure und Funktionen zum delphiinternen kopieren kommt ist mir so neu. Zur Not habe ich wieder was dazu gelernt.

Gruß oki

Roachford 25. Sep 2008 13:42

Re: Funktionsrückgabewert: Array
 
Zitat:

Zitat von oki
Dynamische Arrays sind imho Zeiger auf Speicherbereiche.

Korrekt.

Zitat:

Zitat von oki
Das Setzen einer Variable auf nil die ein dynamisches Array hält reicht aus um das Array zu "lösche".

Dabei greift hier Compilermagic von Delphi, welche implizit ein SetLength(x, 0) damit aufruft und zuvor, wenn nötig, das Array finalisiert.

Zitat:

Zitat von oki
Somit sollte eine Übergabe eines dyn. Arrays in einer Procedure doch die Übergabe eines Zeigers sein. Ist dann überhaupt eine Deklaration als var-Parameter notwendig?

Wenn du var weglässt, erstellt dir Delphi vor Änderungen eine Kopie des Arrays und somit setzt du höchstens die Kopie auf 0.

Mit dem var hingegen legt Delphi dir keine Kopie an sondern übergibt dir den originalen Zeiger auf das Array vom Aufrufer. Somit kannst du das Array auch verändern.

Zitat:

Zitat von oki
Das es bei der Übergabe von dyn. Arrays in Procedure und Funktionen zum delphiinternen kopieren kommt ist mir so neu. Zur Not habe ich wieder was dazu gelernt.

Ich müsste hier vllt. nochmal explizit darauf hinweisen, dass ich die Veränderung des Arrays meine - also von NIL setzen bist SetLength(). Ein Veränderung der Arrayinhalte ohne Grössenänderung ist natürlich ohne var möglich, da er die Daten an der Stelle direkt editiert, welche der Zeiger bestimmt.

Delphi-Quellcode:
program ArrayTest;

{$APPTYPE CONSOLE}

uses
  Types,
  SysUtils;

procedure ChangeContent(AList: TIntegerDynArray);
var
  i: integer;
begin
  for i := low(AList) to high(AList) do
    AList[i] := 10 - i;
end;

procedure ChangeArray(AList: TIntegerDynArray);
var
  i: integer;
begin
  SetLength(AList, 4);
  for i := low(AList) to high(AList) do
    AList[i] := 50 + i;
end;

procedure Test;
var
  lTestCaller: TIntegerDynArray;
  lInt, i: integer;
begin
  SetLength(lTestCaller, 3);

  for i := low(lTestCaller) to high(lTestCaller) do
    lTestCaller[i] := Succ(i);

  WriteLn('content prior ChangeContent():');
  for lInt in lTestCaller do
    WriteLn(lInt);
  WriteLn;

  ChangeContent(lTestCaller);

  WriteLn('content after ChangeContent() & prior ChangeArray():');
  for lInt in lTestCaller do
    WriteLn(lInt);
  WriteLn;

  ChangeArray(lTestCaller);

  WriteLn('content after ChangeArray():');
  for lInt in lTestCaller do
    WriteLn(lInt);
end;

begin
  try
    Test;

    ReadLn;
  except
    on E:Exception do
      Writeln(E.Classname, ': ', E.Message);
  end;
end.
Ausgabe:
Zitat:

Zitat von Command Console
content prior ChangeContent():
1
2
3

content after ChangeContent() & prior ChangeArray():
10
9
8

content after ChangeArray():
10
9
8


oki 25. Sep 2008 13:53

Re: Funktionsrückgabewert: Array
 
ok,

somit ist das Verändern der Inhalte eines dynamischen Arrays innerhalb der Procedure ohne var-Übergabe genauso möglich wie mit var-Übergabe. Um das interne kopieren zu vermeiden, macht es Sinn den Parameter mittels var zu übergeben (was ja eigentlich generell die Übergabe eines Zeigers bewirkt).

Damit ergibt sich aber automatisch, dass Delphi intern die Parameterübergabe für unterschiedliche Typen auch unterschiedlich händelt. Oder wird bei der Übergabe einer Objectinstanz auch intern kopiert? :gruebel:

Gruß oki

Roachford 25. Sep 2008 14:12

Re: Funktionsrückgabewert: Array
 
Zitat:

Zitat von oki
Damit ergibt sich aber automatisch, dass Delphi intern die Parameterübergabe für unterschiedliche Typen auch unterschiedlich händelt. Oder wird bei der Übergabe einer Objectinstanz auch intern kopiert? :gruebel:

Nein, kann er gar nicht, weil dann müsste er einen Copy Constructor haben bzw. eine feste und automatisch erweiterte Funktion wie Assign() haben. Soviel Compilermagic hat Delphi nicht und es würde durch die vielen Zeigertypen (ob versteckt oder offensichtlich) in der Delphi Sprache nicht viel bringen, weil die wären auch mit einem Copy Constructor nil danach. Da hätte er dann noch mehr Probleme zu wissen ob du bei einem Zeigertyp den gleichen Zeiger oder eine neuen Zeiger auf eine Kopie haben willst. Aus dem gleichen Grund handhabt es C++ genauso, wobei es dort mit den reinen Objekten eh nötig ist.

oki 25. Sep 2008 15:14

Re: Funktionsrückgabewert: Array
 
Dann versteh ich aber nicht, warum Delphi ein dynamisches Array als Parameter kopieren soll.

Gruß

Roachford 25. Sep 2008 15:40

Re: Funktionsrückgabewert: Array
 
Dein Objektinstanzenzeiger wird intern kopiert, nur das Objekt kann er nicht kopieren. Beispiel:

Delphi-Quellcode:
procedure Test(AObject: TObject);
begin
  AObject := nil;
end;

procedure Anderes;
var
  lInstance: TObject;
begin
  lInstance := TObject.Create;
  try
    Test(lInstance);
   
    if lInstance = nil then
      WriteLn('nicht kopiert')
    else
      WriteLn('Instanzenzeiger wurde kopiert & Kopie wurde zurück gesetzt');

  finally
    lInstance.Free;
  end;
end;

oki 25. Sep 2008 15:47

Re: Funktionsrückgabewert: Array
 
Ja klar, wenn ich den Parameter nicht als var übergebe, dann bleibt der Zeiger nach außen natürlich "konstant". Ich kann den Inhalt eines Objektes in der Procedure ändern, weil ich auf die enthaltenen Daten zugreife auf dessen Struktur der Zeiger der Instanz zeigt.
Ich dachte nur, dass Delphi das mit allen Zeigern so macht und ein dynamisches Array ist halt ein Zeiger auf den Speicher.

Gruß oki

Roachford 25. Sep 2008 15:52

Re: Funktionsrückgabewert: Array
 
Zitat:

Zitat von oki
Ich dachte nur, dass Delphi das mit allen Zeigern so macht und ein dynamisches Array ist halt ein Zeiger auf den Speicher.

Macht er doch auch. Die TObject Deklaration impliziert ja schon einen Zeiger. Somit kannst du das Beispiel zuvor auch so umbauen, dass du TObject z.B. durch PByte ersetzt, das Verhalten wäre das gleiche.

oki 25. Sep 2008 15:58

Re: Funktionsrückgabewert: Array
 
oh, ich glaub, jetzt reden wir aneinander vorbei. Ich wiederhol noch mal, was ich verstanden habe.

Wird ein dyn. Array in einer Procedure nicht als var-Parameter übergeben, so kopiert Delphi intern alle Daten des Arrays bei der Übergabe, was zu einer erheblichen Anzahl an Operationen führen kann.

Und genau das versteh ich nicht. Die Übergabe der Adresse sollte doch reichen, wie bei der Objectinstanz. :gruebel:
Mir gehts hier also ausschließlich um das Array, nicht um die Objekte.

Gruß

Roachford 25. Sep 2008 16:25

Re: Funktionsrückgabewert: Array
 
Zitat:

Zitat von oki
Wird ein dyn. Array in einer Procedure nicht als var-Parameter übergeben, so kopiert Delphi intern alle Daten des Arrays bei der Übergabe, was zu einer erheblichen Anzahl an Operationen führen kann.

Nein, tut es nicht.

Roachford
Wenn du var weglässt, erstellt dir Delphi vor Änderungen eine Kopie des Arrays und somit setzt du höchstens die Kopie auf 0.


Das "vor Änderungen" bezieht sich nicht auf den Array Inhalt sondern auf das Array selbst.

Roachford
Ich müsste hier vllt. nochmal explizit darauf hinweisen, dass ich die Veränderung des Arrays meine - also von NIL setzen bist SetLength(). Ein Veränderung der Arrayinhalte ohne Grössenänderung ist natürlich ohne var möglich, da er die Daten an der Stelle direkt editiert, welche der Zeiger bestimmt.

oki 25. Sep 2008 17:56

Re: Funktionsrückgabewert: Array
 
Ja, dann haben wir wirklich aneinander vorbei gesprochen. Ich meinte eigentlich die Inhalte.

Dann sollte das jetzt geklärt sein. :mrgreen:

Gruß oki


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:11 Uhr.

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