Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Merkwürdiges Problem mit einem dynamischen Array (https://www.delphipraxis.net/73823-merkwuerdiges-problem-mit-einem-dynamischen-array.html)

thomasdrewermann 24. Jul 2006 15:01


Merkwürdiges Problem mit einem dynamischen Array
 
Hallo,

wenn ich ein dynamisches Array global wir folgt deklarieren will:
Code:
 private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1; var a:Array of Double;


implementation
Bekomme ich vom Compiler folgende Fehler ausgeworfen:
1. Fehler: [ erwartet, aber 'OF' gefunden
2. Fehler: 'OF' erwartet, aber 'implementation' gefunden


Kopiere ich folgende Methoden aus der Delphi-Hilfe in den Quellcode, compiliert er ohne Fehler:
Code:
procedure Clear(var A: array of Double);
var
 I: Integer;
begin
 for I := 0 to High(A) do A[I] := 0;
end;
function Sum(const A: array of Double): Double;
var
 I: Integer;
 S: Double;
begin
 S := 0;
 for I := 0 to High(A) do S := S + A[I];
 Sum := S;
end;

Weiss jemand woran dieses Verhalten liegt? Was mache ich falsch?

Meine Delphi-Version ist 3.

Gruß
Thomas

Klaus01 24. Jul 2006 15:07

Re: Merkwürdiges Problem mit einem dynamischen Array
 
Delphi 3 kann so weit ich das weiß keine dynamischen Arrays.


Delphi-Quellcode:
private
    { Private-Deklarationen } 
  public
    { Public-Deklarationen } 
  end;

var
  Form1: TForm1;

var a:Array [0..10] of Double;

implementation
Grüße
Klaus

Eichhoernchen 24. Jul 2006 15:07

Re: Merkwürdiges Problem mit einem dynamischen Array
 
Ich glaub Delphi 3 unterstützt noch gar keine dynamischen Arrays,
schlagt mich wenn ich falsch liege aber ich meine ich hätte dass mal gelesen!

marabu 24. Jul 2006 15:09

Re: Merkwürdiges Problem mit einem dynamischen Array
 
Nochmal anders formuliert: es ist ein Unterschied zwischen einer dynamischen Array-Variablen und einem offenen Array-Parameter.

Grüße vom marabu

thomasdrewermann 24. Jul 2006 15:10

Re: Merkwürdiges Problem mit einem dynamischen Array
 
Worin lieg denn dieser?

Wie nutze ich Array-Variablen?

Gruß
Thomas

himitsu 24. Jul 2006 15:23

Re: Merkwürdiges Problem mit einem dynamischen Array
 
Du erstellst die 'nen VorlageTypen
Delphi-Quellcode:
Type TMyDoubleArray = Array[0..0] of Double;
daraus wird dann der PointerTyp erstellt/genutzt
Delphi-Quellcode:
Type PMyDoubleArray = ^TMyDoubleArray;
Var MyDoubleVar: PMyDoubleArray;
// oder
Var MyDoubleVar: ^TMyDoubleArray;
und dann mußt du für die Speicherresservierung (z.B. per GetMem/FreeMem/eallocMem) sorgen.
Delphi-Quellcode:
MyDoubleVar := GetMem(x * SizeOf(Double));

thomasdrewermann 24. Jul 2006 15:42

Re: Merkwürdiges Problem mit einem dynamischen Array
 
Nach der Speicherreservierung kann ich das verpointete Array normal nutzen? Also über a[x]?

Gruß
Thomas

DGL-luke 24. Jul 2006 15:49

Re: Merkwürdiges Problem mit einem dynamischen Array
 
jop.

Setlength funktioniert dann natürlich nicht, zur Vergrößerung musst du wieder Speicher alloziieren. (wie geht denn das? den speicherbereich vergrößern? :gruebel: )

thomasdrewermann 24. Jul 2006 15:51

Re: Merkwürdiges Problem mit einem dynamischen Array
 
Vielen Dank!

Dann weiss ich bescheid!

Gruß
Thomas

Khabarakh 24. Jul 2006 15:54

Re: Merkwürdiges Problem mit einem dynamischen Array
 
Zitat:

Zitat von DGL-luke
(wie geht denn das? den speicherbereich vergrößern? :gruebel: )

So wie es SetLength auch macht: Neuen, größeren Speicher reservieren, Inhalt aus dem alten rauskopieren und diesen dann freigeben.

Dax 24. Jul 2006 15:55

Re: Merkwürdiges Problem mit einem dynamischen Array
 
Zitat:

Zitat von DGL-luke
wie geht denn das? den speicherbereich vergrößern? :gruebel:

Delphi-Referenz durchsuchenRealloc ;)

thomasdrewermann 24. Jul 2006 15:56

Re: Merkwürdiges Problem mit einem dynamischen Array
 
Ok

himitsu 24. Jul 2006 16:01

Re: Merkwürdiges Problem mit einem dynamischen Array
 
ReallocMem, oder Realloc, oder wie dat heißt ... siehe OH?
Delphi-Quellcode:
Arr := ReallocMem(Arr, xNew * SizeOf(Double));
// oder so ... jenachdem, ob man da Arr als Var-Parameter übergeben kann
ReallocMem(Arr, xNew * SizeOf(Double))
na ja, oder
Delphi-Quellcode:
var Arr, Temp: TMyArray;

Temp := GetMem(xNew * SizeOf(Double));
Move(Arr, Temp, Min(x, xNew) * SizeOf(Double));
FreeMem(Arr);
Arr := Temp;


Aber es empfiehlt sich natürlich, wenn du irgendwo die Größe speicherst ... weil sowas wie Length(MyDoubleArray) geht natürlich och nicht :zwinker:
Delphi-Quellcode:
Type TMyDoubleArray = Array[0..0] of Double;
  PMyDoubleArray = ^MyDoubleArray;

Var MyDoubleArraySize: Integer;
  MyDoubleArray: PMyDoubleArray;
oder im Typen
Delphi-Quellcode:
Type TMyDoubleArray = Record
    Size: Integer
    Data: Array[0..0] of Double;
  End;
  PMyDoubleArray = ^MyDoubleArray;

Var MyDoubleArray: PMyDoubleArray;

[add]
zu langsam -.-''

Dax 24. Jul 2006 16:14

Re: Merkwürdiges Problem mit einem dynamischen Array
 
In der Codelib sind auch Klassen dafür:dynamische Arrays in Delphi 3

thomasdrewermann 24. Jul 2006 20:43

Re: Merkwürdiges Problem mit einem dynamischen Array
 
Die dynamischen Arrays in der CodeLib sind aber auf einen bestimmten Type spezifiziert oder? Also Integer, Word oder Pointer...

Gruß
Thomas

Der_Unwissende 24. Jul 2006 20:52

Re: Merkwürdiges Problem mit einem dynamischen Array
 
Da Pointer aber auch nur Zeiger auf irgendeinen Speicher sind....
Du müsstest halt nur casten

Gruß Der Unwissende

thomasdrewermann 24. Jul 2006 20:53

Re: Merkwürdiges Problem mit einem dynamischen Array
 
Das heisst ich legen dann jeweils einen zeiger auf das Objekt, welches meine Daten enthält, oder?

Gruß
Thomas

Der_Unwissende 24. Jul 2006 21:17

Re: Merkwürdiges Problem mit einem dynamischen Array
 
Na ja, ein Zeiger muss nicht auf ein Objekt zeigen (sorry wenn ich mal so kleinlich bin). Wenn du Integer Werte speicherst, dann liegen die irgendwo im Speicher (kannst also auch einen Zeiger darauf speichern), das gilt auch für Bytes, Strings, ..., beliebige Klassen.
Ob es Sinn macht einen Zeiger zu speichern ist immer eine andere Sache. Dein Zeiger hat den Vorteil, dass er sehr universell ist. Zudem hat er immer die volle Registerbreite deines OS (i.d.R. also 4 Byte). Jetzt ist ein Byte aber nun mal nur ein Byte groß. Wenn du also Pointer auf das Byte speicherst... Von der Perfomance her wäre es natürlich an sich schlecht Byte zu verwenden (da müssen 3 Byte mit 0en gefüllt werden) und Platz hat man auf heutigen System offensichtlich genug (kenne wenig Programme die da an Speicher sparen, vorallem nicht bei solchen Variablen!)
Wie gesagt, man könnte über den Sinn streiten.

Wenn du ein Array von Pointern verwendest, kannst du so ziemlich alles speichern (eigentlich sogar genau alles). Dann solltest du aber schauen, wie gut die Umsetzung von TList in Delphi 3 ist (vielleicht gibt es dort ja schon eine TList). Diese ist nichts anderes als ein Array of Pointer, das geschickt von Delphi verwaltet wird. So alloziert eine TList automatisch Speicher und gibt ungenutzten auch wieder frei.
Das beantragen und verändern der Speichergröße kostet unabhängig von der eigentlich Größe nahezu konstant viel Zeit. Würdest du also bei jedem neuen Element immer die Länge um 1 vergrößern wird das schnell recht aufwändig. Vergrößerst du das Array gleich um 100 Elemente, so sparst du max. 99 solcher Aufrufe. TList bietet den Vorteil sich genau darum selbst zu kümmern.
Ich weiß wie gesagt nicht wie es da unter Delphi 3 aussieht.

Was ein dynamisches Array angeht, du könntest mit einem Array of Pointer halt alles machen, aber du hast natürlich keine Typsicherheit mehr:

Code:
var a : Array of Pointer; // wie auch immer es dann in einer Delphi 3 Umsetzung aussähe!
    b : Byte;
    i : Integer;
    c : Cardinal;
    o : TObject;
begin
  setLength(a, 4);
 
  b := 0;
  i := -1;
  c := 4000000000;
 
  a[0] := @b;
  a[1] := @i;
  a[2] := @c;

  // noch eine Falle!
  a[3] := @o;
end;
Dieser Code würde funktionieren und du hättest gleich mehrere Fallen. Einerseits siehst du, dass hier 3 unterschiedliche Typen in das Array gepackt wurden. Was sich an der Stelle a[0] befindet ist aber eine 32-Bitige (vielleicht auch schon 64) Adresse. Diese Adresse wird ungleich 0 sein (die Variablen gibt es ja zu dem Zeitpunkt alle und sie sind lokal). Das heißt beim auslesen des Arrays an Stelle 0 könntest du auch in ein Char oder eine TList casten. Ob das glückt ist eine andere Sache!
Das andere Problem ist, du hast hier die Adressen lokaler Variablen stehen. Steht dies in einer Prozedur, würden die Adressen keine Gültigkeit nach dem Ende der Prozedur haben. Gut in diesem Fall wird auch das dynamische Array in dieser Prozedur angelegt, aber wenn es global wäre...
Die Adressen behalten natürlich ihre Gültigkeit (es gibt die Adresse noch), was dort steht ist aber mit dem Ende der Prozedur eher zufällig.
Hier kommt auch die weitere Falle ins Spiel. o ist ein TObject, wie du siehst wird der Konstruktor nie aufgerufen. Die gespeicherte Adresse a[3] kann aber <> nil sein. Dies liegt einfach daran, dass o lokal ist. Lokale Variablen (auch Pointer und Referenzen) sind nicht initialisiert.

Diese Probleme können immer auftauchen, wenn du mit Pointern arbeitest. Deswegen macht man es ja so ungerne. Typsicherheit kann man natürlich leicht durch typisierte Pointer erreichen oder Kapselungen, die dir das einfügen nur von einem bestimmten Datentyp erlauben und aut. casten, wenn du lesend zugreifst.

Gruß Der Unwissende

thomasdrewermann 24. Jul 2006 21:21

Re: Merkwürdiges Problem mit einem dynamischen Array
 
Vielen Dank!
Jetzt komme ich denke ich klar ;-)
Wenn ich noch mal Fragen habe poste ich wieder ... :-)

Gruß
Thomas


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:38 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