Autor Beitrag
Martello
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 131

WIN 2000
TP, C, Delphi 1.0, Turbo Delphi 2006, Delphi 7
BeitragVerfasst: Sa 14.08.10 13:17 
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

ausblenden volle Höhe 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                    //Teste Zeilenzahl
readln(inn);
i:=i+1;
until eof(inn);
reset(inn);               // Gehe zurück zum Dateianfang

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
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8554
Erhaltene Danke: 481

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: 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?

_________________
We are, we were and will not be.
Martello Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 131

WIN 2000
TP, C, Delphi 1.0, Turbo Delphi 2006, Delphi 7
BeitragVerfasst: Sa 14.08.10 16:04 
user profile iconGausi hat folgendes geschrieben Zum zitierten Posting springen:

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.


ausblenden 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);   //Lese zuerst Index
                           // und schreibe dann dorthin alle Daten[Index]

 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


Zuletzt bearbeitet von Martello am Sa 14.08.10 16:18, insgesamt 1-mal bearbeitet
Gausi
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8554
Erhaltene Danke: 481

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: 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?

_________________
We are, we were and will not be.
Martello Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 131

WIN 2000
TP, C, Delphi 1.0, Turbo Delphi 2006, Delphi 7
BeitragVerfasst: Sa 14.08.10 16:34 
user profile iconGausi hat folgendes geschrieben Zum zitierten Posting springen:
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:

ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 334
Erhaltene Danke: 3



BeitragVerfasst: Sa 14.08.10 16:34 
Wenn du die Werte auch außerhalb der Prozedur benutzen willst, musst du mit einem VAR Parameter arbeiten.
ausblenden Delphi-Quelltext
1:
procedure lade_gegend(filename:stringvar Umfeld:Gegend);					


In deiner Ursprünglichen Funktion gibt es auch noch ein Memory Leak, es fehlt am Ende noch ein:
ausblenden Delphi-Quelltext
1:
zeile.free;					


user profile iconMartello hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconGausi hat folgendes geschrieben Zum zitierten Posting springen:

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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 131

WIN 2000
TP, C, Delphi 1.0, Turbo Delphi 2006, Delphi 7
BeitragVerfasst: Sa 14.08.10 16:47 
user profile iconSvenAbeln hat folgendes geschrieben Zum zitierten Posting springen:
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:
ausblenden Delphi-Quelltext
1:
zeile.free;					



Ein grober Pascal-Anfängerfehler, der mir sicher auch vor Jahrzehnten bereits passiert ist.... :?
Vielen Dank für die Korrektur.

Und mit
ausblenden Delphi-Quelltext
1:
zeile.free;					

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
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8554
Erhaltene Danke: 481

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: 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.

_________________
We are, we were and will not be.
elundril
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3747
Erhaltene Danke: 123

Windows Vista, Ubuntu
Delphi 7 PE "Codename: Aurora", Eclipse Ganymede
BeitragVerfasst: 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

_________________
This Signature-Space is intentionally left blank.
Bei Beschwerden, bitte den Beschwerdebutton (gekennzeichnet mit PN) verwenden.
Gausi
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8554
Erhaltene Danke: 481

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: Sa 14.08.10 16:58 
Jup, aber oben wird eine TStringlist "Zeile" erzeugt. Und die muss man mit .free freigeben. :)

_________________
We are, we were and will not be.
elundril
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3747
Erhaltene Danke: 123

Windows Vista, Ubuntu
Delphi 7 PE "Codename: Aurora", Eclipse Ganymede
BeitragVerfasst: 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.

_________________
This Signature-Space is intentionally left blank.
Bei Beschwerden, bitte den Beschwerdebutton (gekennzeichnet mit PN) verwenden.
Martello Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 131

WIN 2000
TP, C, Delphi 1.0, Turbo Delphi 2006, Delphi 7
BeitragVerfasst: Sa 14.08.10 17:04 
user profile iconelundril hat folgendes geschrieben Zum zitierten Posting springen:
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