Autor Beitrag
benner
Hält's aus hier
Beiträge: 7



BeitragVerfasst: Mo 13.10.08 10:04 
Tag zusammen, ich bin neu hier und beschäftige mich erst seit kurzer Zeit mit Delphi. Ich habe eine Klasse geschrieben, die Zahlen aus einer Textdatei einlesen soll. Diese Zahlen sollen in einem dynamischen Array, welches eine Membervariable der Klasse ist, gespeichert werden. Die relevanten Stellen meiner Klasse sind folgende:
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:
unit CReadIn;

interface

uses
    Windows,
    CStructures;

type

    ReadIn = class(TObject)
    public
          function readKoordinates(): Bool;
    public
          ko       : Koordinaten;
    end;

implementation

function ReadIn.readKoordinates():Bool;
var
   tfInFile        : TextFile;
   nX, nY          : Integer;

begin
     assignFile(tfInFile,'koordinaten.txt');
     reset(tfInfile);
     while not eof (tfInFile) do
     begin
          ReadLn(tfInfile, nX,nY);
          SetLength(ko,Length(ko)+1);
          ko[Length(ko)-1].x := nX;
          ko[Length(ko)-1].y := nY;
     
     end;
     CloseFile(tfInFile);

     //temp!
     result := true;
end;
end.


"Koordinaten" ist eine Typdefinition:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
//...
type
    PunktInfo = packed record
            x          : Integer;
            y          : Integer;
            Info       : Bool;
    end;
    Koordinaten = array of PunktInfo;
//...


Wird nun die Methode ReadIn.readKoordinates aufgerufen, erhalte ich eine EAccessViolation. Der Cursor steht in Zeile 31 bei SetLength. Kommentiere ich diese Anweisung aus, tritt der Fehler in Zeile 32 auf. In vergleichbaren Fällen in anderen Foren war stets das SetLength vergessen worden. Deswegen wende ich mich jetzt mal vertrauensvoll an euch :wink:
Wenn ihr noch weitere Tips oder Anmerkungen bezüglich Style etc. habt, immer her damit. Wie gesagt ich bin noch neu bei Delphi =)
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mo 13.10.08 11:15 
Der Fehler dürfte in Zeile 30 auftreten ;-), wenn der Cursor in Zeile 31 steht, schau in die Zeile davor. Meistens wirst du dort fündig.
Bei ReadLn(tfInfile, nX,nY); müsste in der Zeile ja "nX nY" so stehen, vielleicht ist das an einer Stelle nicht der Fall oder es handelt sich um eine Leerzeile am Dateiende?
Noch was anderes, statt
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
     while not eof (tfInFile) do
     begin
          ReadLn(tfInfile, nX,nY);
          SetLength(ko,Length(ko)+1);
          ko[Length(ko)-1].x := nX;
          ko[Length(ko)-1].y := nY;
     
     end;
würde ich das lieber so machen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
     OldLen := Length(ko);
     while not eof (tfInFile) do
     begin
          ReadLn(tfInfile, nX, nY);
          SetLength(ko, OldLen + 1);
          ko[OldLen].x := nX;
          ko[OldLen].y := nY;
          Inc(OldLen);
     end;
Damit sparst du den ständigen Aufruf von Length.
benner Threadstarter
Hält's aus hier
Beiträge: 7



BeitragVerfasst: Mo 13.10.08 11:44 
Vielen Dank für die Antwort erstmal. Deinen Tipp habe ich gleich mal übernommen. Der Code sieht jetzt folgendermaßen aus:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
assignFile(tfInFile,'koordinaten.txt');
     reset(tfInfile);
     oldLength := Length(ko);
     //while not eof (tfInFile) do
     begin
          //ReadLn(tfInfile, nX,nY);
          nX := Random(20);
          nY:= Random (20);
          SetLength(ko,oldLength+1);
          ko[Length(ko)-1].x := nX;
          ko[Length(ko)-1].y := nY;
          if (random > 0.5) then ko[Length(ko)-1].Info := false
          else ko[Length(ko)-1].Info := true;
     end;
     CloseFile(tfInFile);


Ich habe die Schleife mal rausgenommen und nX und nY manuell belegt, um die Fehlerquelle Read(...) auszuschließen. Der Fehler ist allerdings immer noch nicht weg, er tritt jetzt in Zeile 3 auf. Das bestärkt mich in meiner Vermutung, dass es mit dem dynamischen Array zusammenhängt. Nur dass es diesmal eben nicht bei SetLength auftritt, sondern bei Length. Jeglicher Zugriff auf das Array erzeugt diesen Fehler. Muss die Speicherreservierung (also der Aufruf von SetLength) vielleicht an einer anderen Stelle erfolgen? Ich hatte für die Klasse auch schon einen Konstruktor implementiert und versucht SetLength darin aufzurufen, allerdings habe ich wieder die gleiche Fehlermeldung erhalten...
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mo 13.10.08 11:57 
In Zeile 3? Bist du sicher, dass die Datei richtig geöffnet wird? In dem Zusammenhang machst du auf jeden Fall den Fehler keinen Pfad anzugeben, warum das unbedingt nötig ist, habe ich hier ausführlich erklärt, auch mit Demoprogramm:
www.delphi-library.d...iewtopic.php?t=82952

Kannst du den Teil vielleicht in ein Testprojekt stecken und es dort testen? Dann könntest du das einfach mal anhängen, wenn der Fehler auf diesen Quelltext reduziert immer noch auftritt.

// EDIT START
Ich habe es gerade getestet, der Quelltext funktioniert 1:1 wunderbar (abgesehen von der fehlenden Verzeichnisangabe). Entweder ist die Datei fehlerhaft oder folgende Erklärung trifft zu.
// EDIT END

Generell kann es auch sein, dass der Fehler an ganz anderer Stelle verursacht wird, wenn es wirklich so sein sollte, dass der Quelltext an sich so funktioniert. Es könnte sein, dass du an anderer Stelle auf einen falschen Index eines dynamischen Arrays zugegriffen hast und dabei falsche Speicherbereiche überschrieben hast. Sollte das der Fall sein lässt sich der Bug nicht ganz so einfach finden.
Schalte am besten mal die Bereichsüberprüfung in den Compileroptionen der Projektoptionen ein. Dann sollten (in den meisten Fällen, in Ausnahmefällen ist Delphi <= 2006 da leider buggy) Bereichsüberschreitungen beim Zugriff auch auf dynamische Arrays abgefangen und angezeigt werden. Dies solltest du aber nur für Debuggingzwecke aktivieren, da der zusätzliche Prüfcode entsprechend die Performance herabsetzt.

Was deinen zuletzt geposteten Quelltext angeht: Da musst du dann auch noch OldLength erhöhen und statt "Length(ko)-1" auch das benutzen, aber ich vermute mal das liegt jetzt am Testen, dass du das noch nicht drin hast.
benner Threadstarter
Hält's aus hier
Beiträge: 7



BeitragVerfasst: Mo 13.10.08 12:32 
Kurz vor dem Absenden habe ich noch dein Edit gelesen, grade noch rechtzeitig :wink:

Ich habe mal ein neues Projekt erstellt, welches die Problemstellung auf das Wesentliche reduziert und den Fehler reproduziert. Darin kommen keine Dateizugriffe mehr vor und nur ein einzelner Zugriff auf das Array. Daher vermute ich, dass auch deine Erklärung im Sinne von "fehlerhaften Indizes beim Arrayzugriff" in diesem Fall nicht zutrifft. Die Bereichsüberprüfung hat auch nicht weitergeholfen.

Mir ist aber etwas aufgefallen: die Instanz der Klasse ReadIn ist global angelegt. Lege ich diese in der aufrufenden Methode lokal an, funktioniert alles ohne Probleme (ich habe das im Quelltext nochmal markiert). Vielleicht hilft das ja bei der Ursachensuche? Aber diese Lösung ist nicht ausreichend, ich brauche die Instanz global, um jederzeit auf ihre Variablen zugreifen zu können.

Restlos verwirrend wird das für mich, da mein Code bei dir ohne Probleme funktioniert. Dementsprechend wird vermutlich auch das angehängte Projekt ohne Probleme durchlaufen und keine neuen Erkenntnisse bringen :evil:

Spätestens jetzt wirst du vermutlich die Frage nach meiner IDE stellen :wink: Es ist Borland Delphi Professional 5.0
Einloggen, um Attachments anzusehen!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mo 13.10.08 12:37 
Da brauche ich das Projekt gar nicht öffnen in Delphi. Du erzeugst den Reader nirgends, so kann das ja nicht klappen. Dieser Quelltext war bei dir ja nicht dabei, deshalb habe ich den stillschweigend ganz normal hinzugefügt ;-).
Mein Testcode beim Aufruf:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
procedure TForm77.FormCreate(Sender: TObject);
var
  test: ReadIn;
begin
  test := ReadIn.Create;
  test.readKoordinates;
  test.Free;
end;
Btw: Du solltest Klassennamen immer mit einem T beginnen lassen, das ist in Delphi üblich, man sollte sich daran halten. Also TReadIn zum Beispiel statt nur ReadIn, genauso wie TForm etc.

Dafür empfehle ich auch mal den Styleguide:
www.delphi-treff.de/delphi-styleguide/
benner Threadstarter
Hält's aus hier
Beiträge: 7



BeitragVerfasst: Mo 13.10.08 12:57 
Jetzt läuft alles, vielen Dank. Und vielen Dank, dass du dir die Zeit genommen hast und nebenbei noch ein paar Tips abgefallen sind :)

Edit: Das kommt halt davon, wenn man meint, die OOP-Kapitel zu Delphi nur überfliegen zu müssen :oops: