Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - Zugriffsverletzung - dyn. Arrays
Martello - Sa 14.08.10 13:17
Titel: Zugriffsverletzung - dyn. Arrays
Ich habe zufällig auch ein Problem mit dyn. Arrays, die ich zum ersten Mal verwende.
typ gegend = array of record...
Ich möchte Daten aus einer *.csv-Datei in ein Feld einlesen und dann verwenden.
Die dyn. Länge wurde korrekt gesetzt, und die strukturierten Daten aus der Input-Datei-Text wurden meiner Meinung nach auch korrekt eingelesen. Wenn ich aber auf diese Daten zugreifen möchte, tritt jedesmal eine Zugriffsverletzung auf:
wenn Index 0: Fehlermeldung bei Adresse 00000000
..Index 1: ..bei Adresse 00000020
..Index 2: ..bei Adresse 00000040
..Index 3: ..bei Adresse 00000060
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: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42:
| procedure lade_gegend(filename:string; Umfeld:Gegend); var inn: text; i,j: integer; row: string; zeile: Tstringlist;
begin i:=0; assign(inn,filename); reset(inn); zeile:= Tstringlist.create;
repeat readln(inn); i:=i+1; until eof(inn); reset(inn); setlength(umfeld,i); geof_int:=i;
for j:= 0 to i-1 do
begin readln(inn,row); zeile.delimitedtext:=row; showmessage(zeile[4]); with umfeld[j] do begin
Name:= zeile[0]; Zeit:= strtoint(zeile[1]); lat:= strtofloat(zeile[2]); lon:= strtofloat(zeile[3]);; dir:= strtoint(zeile[4]);
end;
end; umfeld:=nil;
close(inn); end; |
Weil es sich intern um Zeiger handelt, habe ich am Ende umfeld:=nil eingefügt. Aber meine Erfahrungen mit Zeigern sind genauso nichtig wie die mit dyn. Arrays :oops:
Hat jemand eine Idee, wo der Fehler liegen könnte?
Gruß
Martello
Gausi - Sa 14.08.10 13:54
Du setzt am Ende den übergebenen Parameter auf Nil, d.h. du investierst viel Arbeit, das "Umfeld" zu füllen, und pfefferst dann das Ganze ins Nirvana, indem du das auf Nil setzt.
Ich würde das Umfeld := Nil einfach mal weglassen. ;-) Wenn das nicht hilft: Wo genau tritt denn der Fehler auf?
Martello - Sa 14.08.10 16:04
Gausi hat folgendes geschrieben : |
Ich würde das Umfeld := Nil einfach mal weglassen. ;-) Wenn das nicht hilft: Wo genau tritt denn der Fehler auf? |
Mir war das auch suspekt; an der Stelle passiert die damit gemeinte Speicherplatzfreigabe tatsächlich um einiges zu früh. :oops:
Aber der Fehler liegt leider woanders.
Während der Typ meines dyn- Arrays in einer eigenen UNIT deklariert wird, vereinbare ich in meiner UNIT1 (Form1) eine Variable mit dem Namen "Areal". Die Datenübergabe von der Datei nach Areal funktioniert von dort aus fehlerfrei. Das anschließende Anzeigen via Button5Klick führt dann aber zu der Fehlermeldung.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| procedure TForm1.Button5Click(Sender: TObject); var i:integer; begin i:=strtoint(edit9.text); edit9.Text:=areal[i].Name; edit10.Text:=inttostr(areal[i].zeit); edit11.Text:=floattostr(areal[i].lat); edit12.Text:=floattostr(areal[i].lon); edit13.Text:=inttostr(areal[i].dir); end; |
Der Fehler kommt mir sehr bekannt vor: Bei meinen ersten Versuchen mit Zeigern trat er auch ständig auf, weil ich versucht hatte auf nicht initialisierte Bereiche zuzugreifen. Daher verzichte ich in meinem Projekt zu nächst auch auf Zeiger und verwende stattdessen testweise erst mal ein dyn. Array für meine Zwecke. Aber intern werden dyn. Arrays - wie ich gelesen habe - wie Pointer verwaltet; irgendwo in der Gegend dürfte daher der Fehler zu finden sein.
Ich habe das dyn. Array testweise zu einem statischen umfunktioniert. Dabei zeigt sich, dass beim Datenauslesen nichts
"herauskommt", die Editfelder 9 bis 13 bleiben leer. Die Zugriffsverletzung tritt nicht mehr auf.
Aber ein anderer Fehler erscheint, der wahrscheinlich mit dem ersten verwandt ist. Warum funktioniert das Dateneinlesen, nicht aber das Auslesen aus meiner "Matrix" alias Array of Record?
Gruß
Martello
Gausi - Sa 14.08.10 16:13
Hat areal wirklich soviele Einträge, d.h. hast du SetLength passend (also mit Länge i+1) vorher aufgerufen? Wie ist areal definiert, lokal, global, al Eigenschaft der Form? Ist das evtl. sogar doppelt deklariert und du greifst auf das "falsche" Array zu?
Martello - Sa 14.08.10 16:34
Gausi hat folgendes geschrieben : |
| Hat areal wirklich soviele Einträge, d.h. hast du SetLength passend (also mit Länge i+1) vorher aufgerufen? Wie ist areal definiert, lokal, global, al Eigenschaft der Form? Ist das evtl. sogar doppelt deklariert und du greifst auf das "falsche" Array zu? |
Ich habe Areal als letzte Variable
var areal.gegend; unmittelbar vor "implementation"definiert.
Gefüllt (also "initialisiert") wird sie durch Klick auf Form1:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| procedure TForm1.Button2Click(Sender: TObject);
begin lade_gegend('c:\ort\ampeln.csv',areal); edit1.Text:=inttostr(geof_int);
end; |
Sie wird also in Form1 vereinbart und dort auch zweimal aufgerufen. Beim ersten Aufruf verwende ich eine Procedure, ("lade_gegend") die in einer anderen unit2 vereinbart ist; aber daran sollte es eigentlich nicht liegen...Meine Testdatei besteht nur aus drei Zeilen; setlength wurde mit 3 korrekt berechnet (siehe meinen ersten Post) , daran liegt es also auch nicht :cry:
Gruß
Martello
SvenAbeln - Sa 14.08.10 16:34
Wenn du die Werte auch außerhalb der Prozedur benutzen willst, musst du mit einem VAR Parameter arbeiten.
Delphi-Quelltext
1:
| procedure lade_gegend(filename:string; var Umfeld:Gegend); |
In deiner Ursprünglichen Funktion gibt es auch noch ein Memory Leak, es fehlt am Ende noch ein:
Martello hat folgendes geschrieben : |
Gausi hat folgendes geschrieben : |
Ich würde das Umfeld := Nil einfach mal weglassen. ;-) Wenn das nicht hilft: Wo genau tritt denn der Fehler auf? |
Mir war das auch suspekt; an der Stelle passiert die damit gemeinte Speicherplatzfreigabe tatsächlich um einiges zu früh. :oops:
|
Umfeld := Nil; gibt keinen Speicher frei, es wird hier nur die Variable auf NIL gesetzt, das Array liegt immer noch im Speicher auch wenn du keinen Pointer mehr darauf hast.
Martello - Sa 14.08.10 16:47
SvenAbeln hat folgendes geschrieben : |
Wenn du die Werte auch außerhalb der Prozedur benutzen willst, musst du mit einem VAR Parameter arbeiten.
In deiner Ursprünglichen Funktion gibt es auch noch ein Memory Leak, es fehlt am Ende noch ein:
|
Ein grober Pascal-Anfängerfehler, der mir sicher auch vor Jahrzehnten bereits passiert ist.... :?
Vielen Dank für die Korrektur.
Und mit
ist das Programm sogar ein wenig eleganter, wohingegen die Speicherbereiche des Arrays nie freizugeben sind, denn ich brauche sie ja schließlich bis zum Programm-Ende.
Aber hätte
umfeld:=nil; nicht doch auch Speicherplatz wieder zu Verfügung gestellt, allein dadurch, dass die intern für das Feld verwendete Variable nicht länger auf Speicher sondern ins Nichts zeigt?
Gruß
Martello
Gausi - Sa 14.08.10 16:51
Mit umfeld := nil gibst du keinen Speicher frei, sondern kehrst den Datenmüll nur unter den Teppich, wo ihn keiner mehr sieht. Das geht solange gut, bis der Speicher voll ist, bzw. der Teppich wegen des ganzen druntergekehrten Mülls an der Decke klebt. ;-)
Wenn du ein Objekt mit Free freigibst, dann bringst du den Müll runter in die Tonne und hast wieder Platz in deinem Zimmer.
elundril - Sa 14.08.10 16:55
Seit wann muss man eigentlich Records mit Free freigeben? Wie ich noch unter D3/D5 gelernt habe musste man das nicht, sondern konnte das Ding wie ne Integer oder String einfach im Raum herumkugeln lassen?
lg elundril
Gausi - Sa 14.08.10 16:58
Jup, aber oben wird eine TStringlist "Zeile" erzeugt. Und die muss man mit .free freigeben. :)
elundril - Sa 14.08.10 17:01
oh, mein Fehler, ich dachte es ist noch immer das Record gemeint. :oops: Ich setz mich jetzt dann mal in ne Ecke, bin still und schäm mich n bissl.
Martello - Sa 14.08.10 17:04
elundril hat folgendes geschrieben : |
Seit wann muss man eigentlich Records mit Free freigeben? Wie ich noch unter D3/D5 gelernt habe musste man das nicht, sondern konnte das Ding wie ne Integer oder String einfach im Raum herumkugeln lassen?
lg elundril |
Vektor:=nil habe ich aus einem wunderschönen Delphi-Buch, das ich für 1 Euro bei ebay erstanden habe. Dort wird Delphi in knapper Form sehr gut von 3 kompetenten Autoren beschrieben. Auch alles was ich persönlich über dyn. Arrays weiß, steht dort. Irgendwie leuchtet das mit "Speicher wieder freigeben" ein, wenn man sich veranschaulicht, dass dyn. Arrays intern als Pointer verwaltet werden.
Gruß
Martello
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!