Thema: Delphi SetLength mein problem

Einzelnen Beitrag anzeigen

Muetze1
(Gast)

n/a Beiträge
 
#12

Re: SetLength mein problem

  Alt 1. Nov 2006, 16:02
Hi!

Zitat von EWeiss:
Im Magnetic thread war ich etwas sauer das du mich hast auflaufen lassen.
Wollte und habe ich meines Wissens nach nicht.

Zitat von EWeiss:
Hättest du direkt gesag das es nicht geht, hätten wir uns anschließende Diskussionen
sparen können.
Dachte das hätte ich. Da ich auch eine Lösung in Delphi anbieten wollte, wollte ich die ganze Zeit wissen, was dieses Speicher schreiben bei der Instanzenadresse bewirkt bzw. macht. Daher hatte ich dies so oft gefragt.

Zitat von EWeiss:
Ich entschuldige mich aber nocheinmal dafür.
Ist Schnee von gestern...

Zitat von EWeiss:
Delphi-Quellcode:
AWindowDescr = array of PWindowDescr;
//Array von Zeigern auf den Record

AWindowDescr = array of TWindowDescr;
//Array auf den Record
Was ist genau der unterschied ?
Beim Ersten hast du ein Array von Zeigern auf den Typ des Records. Wenn du das Array vergrösserst oder verkleinerst stellt dir das Array nur Platz für einen Zeiger pro Eintrag zur Verfügung. Sprich: Du bekommst pro Eintrag 4 Bytes von dem Array gestellt. Dieser zeigt ins Nirvana und nicht auf einen alloziierten Speicherbereich. Aus diesem Grund musst du mit New() dir Speicher alloziieren (in der Grösse des Records - und das macht New() automatisch (die Grösse ermitteln) und gibt dir einen Zeiger auf diesen alloziierten Speicherbereich in Grösse des Records zurück). Durch das Zurückgeben des Pointers wird dieser im Array an der Position eingetragen.

Beim Zweiten hast du ein Array wo jedes Element direkt ein Record ist. D.h. ein Eintrag in dem Array ist SizeOf(TWindowDescr) gross. Du bekommst hier im Gegensatz zum Ersten nicht nur 4 Bytes der erst auf den Record zeigt sondern du hast direkt hier den Record liegen.

Zitat von EWeiss:
Zitat:
also werden hier 101 Elemente angelegt, Zugreifbar mit Index 0 bis 100
Ja stimmt.
Es gab da ein problem wenn ich mit dem Array(0) begonnen habe die Daten zu füllen
werde ihn auf 99 setzen muss dann allerdings schauen ob nach allen änderungen
wieder ein AV auftritt.
Wieso 99? Ich verstehe es nicht. Ich weise nochmals auf den Unterschied bei den Begrifflichkeiten der Indexe und der Anzahl hin! Wenn ein Array 100 Elemente hat, dann sind die Index 0 bis 99 gültig. Da 0 auch ein gültiger Eintrag ist, wird 0 mitgezählt. Daher ist immer zu unterscheiden ob es nun um die Anzahl der Elemente geht oder um den höchsten Index. Der höchste Index ist bei einem dynamischen Array immer eins unter der Anzahl der Elemente!

Zitat von EWeiss:
Zitat:
warum holst du dir den Speicher für nur einen Record (den an Index 100)? Was ist der Sinn?
Ich habe gelesen das New eine ähnliche funktion wie Redim in VB ist.
Bin aber mittlerweile darauf gekommen das dadurch zuerst der Index(100) mit Daten gefüllt wird.
Ist also verkehrt meine vermutung.
Redim würde in Delphi dem SetLength() entsprechen und New()/Dispose() sind Delphi Funktionen um Speicher zu alloziieren und frei zu geben. Dabei sind New() und Dispose() vergleichbar mit GetMem() und FreeMem() aber mit dem Unterschied, dass New()/Dispose() den Typ mit auswerten und entsprechend der Grösse des Typens den Speicher alloziieren (siehe Delphi-Referenz durchsuchenSizeOf()). GetMem()/FreeMem() wollen immer die Grösse des Speicherbereichs übergeben bekommen.

Zitat von EWeiss:
Zitat:
Ich glaube der erste Parameter müsste noch ein ^ bekommen, weil sonst
schreibt ZeroMemory die Array-Pointer-Liste mit 0'en voll anstatt des Records
Könntest du mir bitte genau die function 'ZeroMemory' erklären ?
Welche parameter genau was machen.
ZeroMemory() ist ein von der MSDN übernommenes Makro zum leeren des Speichers. Dieses verlangt einen Pointer und einen Integer. Der Pointer gibt den mit 0'en aufzufüllenden Speicher an und der Integer die Grösse des Speicherbereichs in Bytes. Ich hatte das mit dem ^ falsch geschrieben. Ich hatte gestern an FillChar() gedacht, da wäre der Parameter kein Pointer sondern ein Var Parameter und dort wäre das ^ nötig gewesen. Bei ZeroMemory() sollte von daher das ^ auch bei einem Array Of PWindowDescr nicht nötig sein.

Zitat von EWeiss:
Zitat:
SetLength(wDescr, High(wDescr) + 10);
High() gibt dir den höchsten Index an, aber nicht die Anzahl der Elemente.
SetLength() will die Anzahl der neuen Elemente, also Anzahl der Elemente bisher + 10, sprich:
SetLength(wDescr, Length(wDescr) + 10);
Habe angenommen das der höchste wert high(wDescr) = 100 wenn Index= 99 geändert .. mit 10 addiert werden kann.
Wäre auch irgendwie logisch. ?
Nein, wie oben beschrieben. Length() liefer die Anzahl der Elemente im Array. High() liefert den höchsten Index im Array. Und bei einem dynamischen Array gilt immer: Höchster Index = Anzahl Elemente - 1. Mit anderen Worten: High(Array) = Length(Array) - 1.

Zitat von EWeiss:
Zitat:
New(wDescr[IntI]);
beachte hier: es ist der Index 100 schon initialisiert!
Ja. aber nicht der 110 wenn mehr als 100 Fenster gefunden wurden. Oder ?
Ich bezog mich damit auf das Array Of PWindowDescr. Da wäre, wie oben beschreiben, jeder Eintrag des Arrays ein Zeiger in 's Datennirvana und daher müsste für jeden Eintrag mit New() Speicher angefordert werden und der Zeiger auf diesen in das Array eingetragen werden. New() alloziert bei deinem Aufruf nur einmail den Speicher für einen Record und legt den Zeiger auf diesen in dem Array ab. Daher wäre nur ein einziger Arrayeintrag initialisiert und alle anderen auch weiterhin undefiniert.

Zitat von EWeiss:
Zitat:
ZeroMemory(wDescr[IntI], SizeOf(wDescr[IntI]^));
siehe oben: 1. Parameter sollte noch ein ^ bekommen
wenn ich das Array AWindowDescr = array of TWindowDescr; setze kommt nun nach der änderung von
ZeroMemory(wDescr[IntI]^, SizeOf(wDescr[IntI]^)); folgende Fehlermeldung
[Pascal Error] Unit2.pas(235): E2017 Pointer type required
lasse ich den Zeiger^ weg diese
[Pascal Error] Unit2.pas(235): E2010 Incompatible types: 'Pointer' and 'TWindowDescr'
Vorher hatte ich bei AWindowDescr = array of PWindowDescr; keine Fehlermeldungen.
Wo ist nun der unterschied ?
Wie oben beschrieben: Vorher hattest du ein "Array Of Pointer auf bestimmten Typ" und nun hast du ein "Array Of bestimmten Typ". Einen Zeiger kann man dereferenzieren (Was das ^ macht), d.h. an der Stelle wo das ^ angehangen wird, wird nicht mit dem Zeiger gearbeitet sondern mit der Stelle wo er hinzeigt. Dies geht bei einem Array Of Record nicht mehr - da ist kein Pointer.

Zitat von EWeiss:
Zitat:
SetLength(wDescr, IntI);
wenn du oben das mit dem Inc(IntI) änderst, dann hier Succ(IntI) als höchstes Element setzen
Verstehe ich auch nicht ganz ?
Nach dem durchlauf der Schleife hat doch IntI autmatisch den höchsten index
warum muss er dann mit Succ(IntI) explizit zugewiesen werden ?
Zuvor hast du den Inc(IntI) am Anfang der Repeat/Until gemacht und damit ist nach der Schleife IntI der höchste Index - aber du hast zu dem Zeitpunkt aber IntI + 1 Einträge (auch hier wieder höchster Index <> Anzahl Elemente!). Daher würde ein SetLength() auf IntI zur Freigabe des letzten Eintrages führen. Succ() liefert den Nachfolger, also würde bei einem Integer IntI im Endeffekt IntI + 1 rauskommen, was wiederrum der Anzahl der Einträge entspricht, da nun der 0. Index mitgezählt wurde. Siehe dazu auch den Zusammenhang: High(Array) = Length(Array)-1. SetLength() möchte immer die Anzahl und Length() liefert immer die Anzahl und nicht den höchsten Index.
  Mit Zitat antworten Zitat