[gelöst] Daten aus Record mit Dyn.Array in Datei speichern

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut

[gelöst] Daten aus Record mit Dyn.Array in Datei speichern

Beitragvon willi4willi » 30. Nov 2018, 21:09 [gelöst] Daten aus Record mit Dyn.Array in Datei speichern

Ich habe ein einfaches Programm, das Daten in eine Datei schreibt und wieder liest.
Es funktioniert auch, wie es soll, aber es lässt sich nicht mehr beenden.

Das Wort "Ende" schreibt es noch und dann bleibt es hängen.

Code: Alles auswählen
 
program project1;
uses sysutils;
 
Type
  TBoolArray = array of boolean;
  TLongWordArray = array of longword;
 
  TSpeicher = Record
               Inputs : TBoolarray;
               Outputs : TBoolarray;
               Counters : TLongWordArray;
              end;
 
var Daten1, Daten2 : TSpeicher;
 
    i: Integer;
    f: THandle;
 
begin
  f:=FileCreate('Daten1.dat');
  If F=-1 then Halt(1);
 
  setlength(Daten1.Inputs,1);
  setlength(Daten1.Outputs,1);
  setlength(Daten1.Counters,4);
 
  setlength(Daten2.Inputs,1);
  setlength(Daten2.Outputs,1);
  setlength(Daten2.Counters,4);
 
  Daten1.Inputs[0]:=TRUE;
  Daten1.Outputs[0]:=TRUE;
  Daten1.Counters[0]:=1;
  Daten1.Counters[1]:=2;
  Daten1.Counters[2]:=3;
  Daten1.Counters[3]:=4;
 
 
  FileWrite(F,Daten1,SizeOf(Daten1));
  FileClose(F);
 
 
  F:=FileOpen ('Daten1.dat',fmOpenRead);
  If F=-1 then Halt(1);
  FileRead(F,Daten2,SizeOF(Daten2));
  FileClose(F);
 
  Writeln(Daten1.Inputs[0]:10,Daten1.Outputs[0]:10);
  Writeln(Daten2.Inputs[0]:10,Daten2.Outputs[0]:10);
  For i:=0 to 3 do Write(Daten1.Counters[i]:10); Writeln;
  For i:=0 to 3 do Write(Daten2.Counters[i]:10); Writeln;
 
//  Readln;
 
// das hier habe ich nachträglich eingefügt, da ich die dyn. Arrays in Verdacht hatte - ohne Erfolg
  setlength(Daten1.Inputs,0);
  setlength(Daten1.Outputs,0);
  setlength(Daten1.Counters,0);
  setlength(Daten2.Inputs,0);
  setlength(Daten2.Outputs,0);
  setlength(Daten2.Counters,0);
 
  Daten1.Inputs:=nil;
  Daten1.Outputs:=nil;
  Daten1.Counters:=nil;
  Daten2.Inputs:=nil;
  Daten2.Outputs:=nil;
  Daten2.Counters:=nil;
 
  Writeln('Ende');
end.
 
 


Als Fehlermeldung kommt ein Exception-Klasse External: SIGSEGV. Bei Adresse 409ACE :roll:

Debugger ausschalten brachte nichts. Array mit fester Länge funktioniert, ist aber keine Lösung. Auch die Array-Größe auf null setzen brachte nichts.

Ich verwendete Windows 10 und Laz. 1.8.4 (FPC 3.0.4) bzw. 1.9.0 (FPC 3.1.1).

Hat jemand eine Idee, was ich falsch mache?
Zuletzt geändert von willi4willi am 3. Dez 2018, 17:36, insgesamt 1-mal geändert.
Viele Grüße

Willi4Willi

------------
willi4willi
 
Beiträge: 109
Registriert: 1. Nov 2008, 18:06
OS, Lazarus, FPC: Windows (10), Linux (debinan) / FPC 3.0.4 / Lazarus 1.8.4 | 
CPU-Target: i386, win64, arm
Nach oben

Beitragvon wp_xyz » 30. Nov 2018, 21:56 Re: Daten aus Record mit Dyn.Array in Datei speichern

Dynamische Arrays sind wie Strings letztendlich Pointer - leider ist im Gegensatz zum klassichen Pascal heuzutage das Pointer-Häkchen oft nicht mehr nötig, so dass man nicht immer erkennt, ob eine Variable ein Pointer ist oder nicht. Da dein Record TSpeicher drei dynamische Arrays enthält, schreibst du also die drei Pointer in die Datei, aber nicht die Daten worauf sie zeigen. Und wenn du später die Datei einliest, werden die Pointer wieder gelesen - nur zeigen sie irgendwohin, auf keinen Fall auf die erwarteten Daten.

Ein dynamisches Array musst du so in die Datei schreiben, dass zunächst die Array-Länge geschrieben wird, denn die Leseroutine weiß das sonst nicht. Anschließend werden die Array-Elemente geschrieben, trivialerweise in einer Schleife Element für Element, aber es geht auch schneller indem du in der Schreibprozedur das erste Element angibst und dann die gesamte Byte-Größe aller Elemente, was sich errechnet als Länge des Array mal Größe jedes Elements - die Elemente stehen ja unmittelbar hintereinander im Speicher - auf diese Weise werden alle Elemente auf einmal geschrieben.
Code: Alles auswählen
// Schreib-Routine
var
  n: Integer;
begin
  n := Length(Daten1.Inputs);
  FileWrite(F, n, SizeOf(n));
  FileWrite(F, Daten1.Inputs[0], n*SizeOf(boolean));
  n := Length(Daten1.Outputs);
  FileWrite(F, n, SizeOf(n));
  FileWrite(F, Daten1.Outputs[0], n*SizeOf(boolean));
  n := Length(Daten1.Counters);
  FileWrite(F, n, SizeOf(n));
  FileWrite(F, Daten1.Counters[0], n*SizeOf(LongWord));

Zum Lesen musst du in exakt derselben Reihenfolge vorgehen: Länge lesen, Speicher reservieren per SetLength, Elemente einlesen
Code: Alles auswählen
// Lese Routine
var
  n: Integer;
begin
  FileRead(F, n, Sizeof(n));
  SetLength(Daten2.Inputs, n);
  FileRead(F, Daten2.Inputs[0], n*SizeOf(boolean));
 
  FileRead(F, n, SizeOf(n));
  SetLength(Daten2.Outputs, n);
  FileRead(F, Daten2.Outputs[0], n*SizeOf(boolean));
 
  FileRead(F, n, SizeOf(n));
  SetLength(Daten2.Counters, n);
  FileRead(F, Daten2.Counters[0], n*SizeOf(LongWord));
...

Das kann man sicher durch spezielle Schreib/Leseprozeduren vereinfachen, aber ich will hier nur das Prinzip zeigen.
wp_xyz
 
Beiträge: 2702
Registriert: 8. Apr 2011, 08:01

Beitragvon willi4willi » 3. Dez 2018, 17:46 Re: [gelöst] Daten aus Record mit Dyn.Array in Datei speiche

Es hat so funktioniert.

Ich dachte der Übergang vom statischen zum dynamischen Array wäre, einfach die Größe wegzulassen und zur Laufzeit mit setlength festzulegen.
Aber wenn die Variable nur den Zeiger speichert, dann erklärt das alles.

Danke!
Viele Grüße

Willi4Willi

------------
willi4willi
 
Beiträge: 109
Registriert: 1. Nov 2008, 18:06
OS, Lazarus, FPC: Windows (10), Linux (debinan) / FPC 3.0.4 / Lazarus 1.8.4 | 
CPU-Target: i386, win64, arm
Nach oben

• Themenende •

Zurück zu Freepascal



Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 2 Gäste

porpoises-institution
accuracy-worried